2011-03-10 65 views
2

有無以下代碼問題與委託返回類型

public delegate object ParseHandler(string s); 
public static ParseHandler GetParser(Type t) 
{ 
    MethodInfo parse = t.GetMethod("Parse", BindingFlags.Static | BindingFlags.Public, 
     null, new Type[] { typeof(string) }, null); 

    if (parse != null) 
     return (ParseHandler)Delegate.CreateDelegate(typeof(ParseHandler), parse, true); 

    return null; 
} 

是在Delegate.CreateDelegate()呼叫與吹「錯誤結合靶的方法」。顯然是因爲ParseHandler被定義爲返回object而不是類型特定的返回值。

我不知道類型在編譯類型,所以我不能取代type參數與通用(如果我做了,那麼整個功能將不需要)。

對如何處理這個有點困惑。所需的行爲是爲給定類型找到public static Parse(string)方法,並創建一個委託讓它稍後調用。

+0

您是否嚴格禁用.NET 2.0平臺? – 2011-03-10 18:01:26

+1

你能向我們展示它失敗的'Parse'方法的聲明嗎? – Ani 2011-03-10 18:03:44

+0

也許你想寫的東西就像我的'解析'https://github.com/CodeInChaos/ChaosUtil/blob/master/Chaos.Util/Conversion.cs,除非你可能需要替換一些'T'對象。 – CodesInChaos 2011-03-10 18:09:01

回答

5

只要真實的返回值是一個引用類型,它就應該沒問題 - 但這對於值類型返回值失敗是有意義的。 (見埃裏克利珀的約representation and identity職位更詳細的解釋。)

一種選擇是創建一個通用類是這樣的:

public class BoxingParserDelegate<T> 
{ 
    private readonly Converter<string, T> parser; 

    public BoxingParserDelegate(Converter<string, T> parser) 
    { 
     this.parser = parser; 
    } 

    public object Parse(string x) 
    { 
     return parser(x); 
    } 
} 

在你GetParser方法,你會檢查是否parse返回類型是一個值類型,如果是這樣的話,通過反射創建一個BoxingParserDelegate<T>的實例。然後,您可以從BoxingParserDelegate的Parse方法創建ParseHandler實例。

這一切都會坦率地說有些尷尬,但應該工作。說實話,感覺應該有一個更簡單的方法。

(在.NET 3.5或更高版本我推薦使用表達式目錄樹,但我剛剛看到的.NET 2.0的標籤。)

編輯:啊哈,以爲稍微簡單的辦法:

public static ParseHandler BuildParseHandler<T>(Converter<string, T> converter) 
{ 
    // Performs boxing automatically 
    return delegate(string x) { return converter(x); } 
} 

這是有效要求編譯器爲您完成上述工作的一半。那麼你只需要確定是否需要調用它,並在必要時用反射來完成。類似這樣的:

public static ParseHandler GetParser(Type t) 
{ 
    MethodInfo parse = t.GetMethod("Parse", 
     BindingFlags.Static | BindingFlags.Public, 
     null, new Type[] { typeof(string) }, null); 

    // Method not found 
    if (parse == null) 
    { 
     return null; 
    } 

    // Reference type - use delegate covariance 
    if (!parse.ReturnType.IsValueType) 
    { 
     return (ParseHandler) Delegate.CreateDelegate(typeof(ParseHandler), 
      parse, true); 
    } 

    // Tricky situation: call BuildParseHandler with generics 
    Type delegateType = typeof(Converter<,>).MakeGenericType(typeof(string), 
                  parse.ReturnType); 
    object converter = Delegate.CreateDelegate(delegateType, parse, true); 

    // You may need extra work to get this... let me know whether or not it works. 
    // Obviously if you make it private, you'll need extra binding flags. 
    MethodInfo method = typeof(TypeContainingThisMethod) 
          .GetMethod("BuildParseHandler"); 
    method = method.MakeGenericMethod(parse.ReturnType); 

    return (ParseHandler) method.Invoke(null, new object[] { converter }); 
} 
+0

這很好,但我建議使用'Converter '來代替;該OP是在.NET 2上。 – Ani 2011-03-10 18:21:41

+0

@Ani:謝謝,將會編輯。 – 2011-03-10 18:22:44

+0

除非我在這裏丟失了一些東西,這歸結於創建'Func 解析器'的實例,這正是我的問題擺在首位。我不能把T當作通用的。 – 2011-03-10 18:25:21