Я хочу создать метод, который возвращает Func <>. Внутри этого метода мне нужно создать делегат или лямбда-выражение, которое точно соответствует типу возвращаемого значения.
В целом это должно выглядеть так:
// 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" );
Внутри MissingMethod () он должен выглядеть следующим образом:
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 ) );
}
Я думаю, что единственный способ получить мой MissingMethod () - это использовать mirror.emit.
Знаете ли вы хорошие ресурсы или учебные пособия по испусканию лямбды или делегата?
Видите ли вы другое возможное решение этой проблемы?
РЕДАКТИРОВАТЬ:
Вот сценарий того, что я хочу достичь:
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" );
// ...
}
}
Я пытаюсь реализовать метод Container и Resolve (). Я знаю, что зарегистрирован тип Foo. И я знаю, что его конструктору нужна строка для вызова.
Когда мне нужно разрешить тип "ConsumerClass", я вижу, что он хочет ввести Func. Это не совсем то, что может предоставить мой контейнер, потому что обычно он предоставляет Foo единственные элементы доступа, например:
Container.Resolve<Foo>( "argument" );
Но, тем не менее, контейнер должен иметь возможность предоставлять Func. Он имеет всю необходимую информацию.
Но теперь я застрял в создании этого связанного Func <,>. И помните, это тоже может быть Func <,,,>. Поэтому я ищу решение, которое может создать моих делегатов на лету. Они должны быть отлиты до точного связанного типа.
EDIT:
Я не уверен, как это лучше описать ... Я пытаюсь сделать что-то вроде this . Но я не хочу передавать цель. Вместо
delegate void object LateBoundMethod( object target, object[] arguments );
мой делегат должен выглядеть как
delegate void object LateBoundMethod( object[] arguments );
и цель указана в качестве поля экземпляра. Принимая и улучшая решение Марка, я получаю:
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 );
}
Но это еще не все. Метод Resolve () больше не является статическим (потому что ему нужно два поля экземпляра) и не может быть вызван. Таким образом, проблема здесь
var callEx = Expression.Call( null, typeof( FuncFactory ).GetMethod( "Resolve" ), argsArray );
Вместо того, чтобы передавать нулевое значение в качестве первого аргумента, я думаю, что мне нужна ссылка на «это». Как мне это сделать?