2010-06-20 16 views
1
class MyClass 
{ 
    public event Action<string> OnAction; 
    public event Func<string, int> OnFunc; 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     MyClass mc = new MyClass(); 

     /// I need to handle arbitrary events. 
     /// But I see no way to create anonymous delegates in runtime 
     /// with arbitrary returns and parameters. So I choosed to 
     /// create multiple 「signatures」 with different parameter 
     /// number (up to 10) and different returns (either the Action or 
     /// Func). While Actions<> work pretty well, the Funcs<> do not. 
     Action<dynamic> someAction = delegate(dynamic p1) { }; 
     Func<dynamic, dynamic> someFunc = delegate(dynamic p1) { return 42;}; 

     // OK 
     mc.OnAction += someAction; 

     // Error: 「Cannot implicitly convert type 'System.Func<dynamic,dynamic>' 
     // to 'System.Func<string,int>'」 
     mc.OnFunc += someFunc; 

     // It doesn't work this way as well (the same error message): 
     // dynamic someFunc = new Func<dynamic, dynamic>((dynamic n1) => { return 42; }); 

     // Let's try another way 
     // 1: 
     // Cannot convert anonymous method to delegate type 'System.Func<string,int>' 
     // because the parameter types do not match the delegate parameter types. 
     // 2 (even more funny): 
     // Parameter 1 is declared as type 'dynamic' but should be 'string'. 
     mc.OnFunc += delegate(dynamic p1) { return 42; }; 
    } 
} 

它爲什麼適用於行爲而不適用於功能? 換句話說,我只是想知道爲什麼Action<dynamic> → Action<string>沒問題,而Func<dynamic,dynamic> → Func<string, int>不是。謝謝。.NET4:如何將動態綁定應用於具有返回值的匿名代理?

回答

0

您的Action和Func定義的唯一區別是Action沒有返回類型。如果你改變你的代碼:

mc.OnFunc += new Func<dynamic, dynamic>(someFunc);// += someFunc; 

mc.OnFunc += new Func<dynamic, int>(someFunc);// += someFunc; 

它的工作原理。

+0

但我不能那樣做。我需要一個通用解決方案。 – Yegor 2010-06-20 16:43:56

+0

@Entrase,沒有這樣的東西作爲一個通用的解決方案...如果你正在尋找普遍的答案,它是42;) – 2010-06-20 17:10:37

+0

讓我們留在上下文中。我不是在尋找生命的意義。我只想知道爲什麼動作→動作是好的,而Func →Func 不是。請告訴我,如果你知道。 – Yegor 2010-06-20 18:18:11

1

如果C#正在期待返回類型爲int的委託,則聲明返回dynamic的委託不兼容。您的委託被聲明爲Func<dynamic, dynamic>,並且C#是強類型的。它不關心你的函數是否實際返回一個int並接受一個字符串;它仍然被宣佈爲Func<dynamic, dynamic>

爲什麼如果你認爲這個例子的代碼不編譯是顯而易見的原因是:

Func<string, int> myFunc = delegate(string foo) { return 42; };  
int result = myFunc("Foo"); 

// If this was allowed... 
Func<dynamic, dynamic> otherFunc = delegate(string foo) { return 42; }; 
myFunc = otherFunc; 
result = myFunc("Foo"); 

// Then this would also be allowed but would be a run-time error. 
otherFunc = delegate(string foo) { return "Bar"; }; // Valid 
myFunc = otherFunc; 
result = myFunc("Foo"); // Oops... an int isn't returned. 
+0

爲什麼動態綁定/轉換工作的參數,並不適用於退貨? – Yegor 2010-06-21 03:56:52

0

好吧,我知道了。

的行動定義如下:delegate void Action <in T> (T arg);,而FUNC是這樣的:delegate TResult Func <in T, out TResult> (T arg);的問題是在關鍵字,這表明協方差而不是逆變如關鍵字一樣。同時typeof(dynamic) == typeof(object)是真的。所以動態,作爲一個更普遍的類型,不是我們所採取的任何協變。嗯,我還以爲動態綁定更加靈活「

延伸閱讀:http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx

順便說一句,報價,我發現那裏算賬:

你可以,如果它是標誌着一個泛型類型參數的協變僅用作方法返回類型,不用作正式方法參數的類型。 反之亦然,如果它僅用作一種形式方法參數並且不用作方法返回類型,則可以將類型標記爲逆變。