2009-06-02 73 views
3

我想發出一個返回Func <>的方法。在這個方法裏面,我必須創建一個委託或lambda表達式,它精確地爲返回類型提供服務。如何發出委託或lambda表達式

總之它應該是這樣的:

// 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()是,以使用reflection.emit。

你知道有關發射lambda或委託的好資源或教程嗎?

您是否看到另一個解決此問題的解決方案?

編輯:
這裏是什麼,我想才達到一個情景:

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"); 
    // ... 
    } 
} 

我想實現容器和決心()方法。我知道有一個「Foo」類型註冊。我知道它的構造函數需要一個字符串來調用。

當我必須解析「ConsumerClass」類型時,我發現它想要注入一個Func。這不正是我的容器可以提供,因爲通常它提供單instaces到美孚這樣的:

Container.Resolve<Foo>("argument"); 

但儘管如此容器應能提供函數求了。它具有所需的所有信息。

但是現在我被困在創建這個綁定的Func <,>中。並記住它也可能是Func < ,,,>。所以我正在尋找一種可以即時創建我的代表的解決方案。他們必須可以澆注到確切的綁定類型。

編輯:
我不知道該怎麼形容好...我試圖做類似this。但我不想通過一個目標。取而代之的

delegate void object LateBoundMethod(object target, object[] arguments); 

我代表應該像

delegate void object LateBoundMethod(object[] arguments); 

,目標是作爲一個實例字段。通過服用和改進Marc的解決方案,我得到:

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); 

而不是作爲第一個參數傳遞null我認爲我需要對'this'的引用。我怎麼做?

+1

我得說我不知道​​我得到的是什麼,你現在要做的,但會使得MissingMethod方法一般不是100%讓你解決問題的一半?或者這不是一個選擇? – kastermester 2009-06-02 14:48:21

+0

另外,我確實得到這樣一個事實:爲了覆蓋所有可能的Func <>泛型,您必須多次編寫代碼,但正如Marc所說,您必須以任何方式對其進行硬編碼。 – kastermester 2009-06-02 14:49:37

回答

7

的第一個問題是,Func<...>不存在 - 你需要單獨的代碼Func<>Func<,>Func<,,>Func<,,,>

現在;我瞭解代碼,但我不確定你想要解決的情況是什麼......你能澄清一下嗎?有可能更好的選擇...

如果它聽起來很複雜,自定義Expression可能是最合適的選擇(比Reflection.Emit簡單得多)。


這工作,例如...

static Delegate MissingFunc(Type result, params Type[] args) 
{ 
    int i = 0; 
    var param = Array.ConvertAll(args, 
     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 body = Expression.Convert(Expression.Call(
       null, typeof(Program).GetMethod("Resolve"), 
       argsArray), result); 
    return Expression.Lambda(body, param).Compile(); 
} 
static void Main() 
{ 
    var func2 = MissingFunc(typeof(string), typeof(int), typeof(float)); 
} 
public static object Resolve(params object[] args) { 
    throw new NotImplementedException(); 
}