Hello,
I want to emit a method that returns a Func<>. Inside this method I have to create a delegate or a lambda expression which exactly serves the return type.
Altogether it should look like this:
// I have a resolve method that will be called inside my missing method
// This is it's signature:
object Resolve( params object[] args);
// This is how I use it:
var barFactory = ( Func<IBar> )MissingMethod( typeof( IBar ) );
var bar = barFactory.Invoke();
// or - with one string argument:
var fooFactory = ( Func<string, IFoo> )MissingMethod( typeof( IFoo ), typeof( string ) );
var foo = fooFactory.Invoke( "argument for foo" );
Inside the MissingMethod() it should look like:
object MissingMethod( Type returnType, params Type[] argTypes )
{
// Create the type of Func<> based on the passed returnType and the argTypes
var funcType = typeof(Func<,...,>).MakeGenericType( ... )
// Here I have to use the Resolve() method and cast the lambda to the correct type
return (cast to funcType)( (arg1, arg2) => Resolve( arg1, arg2 ) );
}
I think that the only way to get my MissingMethod() is, to use reflection.emit.
Do you know good resources or tutorials about emitting a lambda or a delegate?
Do you see another possible solution for this problem?
EDIT:
Here is a scenario of what I want to achive:
static void Main()
{
var container = new Container();
container.Register<Foo>();
container.Register<ConsumerClass>();
var consumerClass = Container.Resolve<ConsumerClass>();
}
class Foo()
{
public Foo( string argument ) {}
}
class ConsumerClass
{
public ConsumerClass( [Inject] Func<string, Foo> factory )
{
var foo1 = factory.Invoke( "first foo" );
var foo2 = factory.Invoke( "another foo" );
// ...
}
}
I am trying to implement the Container and the Resolve() method. I know that there is a "Foo" type registered. And I know that its constructor needs a string to be invoked.
When I have to resolve the type "ConsumerClass" I see that it wants to get a Func injected. That is not exactly what my container can provide, because normally it provides single instaces to Foo like this:
Container.Resolve<Foo>( "argument" );
But nevertheless the container should be able to provide a Func, too. It has all informations needed.
But now I am stuck in creating this bound Func<,>. And remeber it could be a Func<,,,>, too. So I am looking for a solution that can create my this delegates on the fly. They have to be castable to the exact bound type.
EDIT:
I am not sure how to describe it better ... I am trying to do something like this. But I do not want to pass a target. Instead of
delegate void object LateBoundMethod( object target, object[] arguments );
my delegate should look like
delegate void object LateBoundMethod( object[] arguments );
and the target is provided as an instance field. By taking and 'improving' the solution of Marc I get:
private Delegate CreateDelegate( Type returnType, Type[] parameterTypes )
{
m_Type = returnType;
var i = 0;
var param = Array.ConvertAll( parameterTypes, arg => Expression.Parameter( arg, "arg" + i++ ) );
var asObj = Array.ConvertAll( param, p => Expression.Convert( p, typeof( object ) ) );
var argsArray = Expression.NewArrayInit( typeof( object ), asObj );
var callEx = Expression.Call( null, typeof( FuncFactory ).GetMethod( "Resolve" ), argsArray );
var body = Expression.Convert( callEx, returnType );
var ret = Expression.Lambda( body, param ).Compile();
return ret;
}
private readonly Container m_Container;
private Type m_Type;
public object Resolve( params object[] args )
{
return m_Container.Resolve( m_Type, args );
}
But this is incomplete. The Resolve()-method is not static anymore (because it needs two instance fields) and cannot be called. So the problem here is
var callEx = Expression.Call( null, typeof( FuncFactory ).GetMethod( "Resolve" ), argsArray );
Instead of passing null as the first argument I think I need a reference to 'this'. How do I do that?