.NET4: Как применить динамическое связывание к анонимным делегатам с возвратами? - PullRequest
1 голос
/ 20 июня 2010
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> - нет. Спасибо.

Ответы [ 3 ]

1 голос
/ 20 июня 2010

Если 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 голосов
/ 21 июня 2010

Хорошо, я понял.

Действие определяется следующим образом: delegate void Action <in T> (T arg);, тогда как функция выглядит следующим образом: delegate TResult Func <in T, out TResult> (T arg); Проблема в out ключевом слове, котороеуказывает на ковариацию, но не на контрастность, как это делает в ключевом слове.В то же время typeof(dynamic) == typeof(object) верно.Так что dynamic , как более общий тип, не ковариантен тому, что мы берем.Хм, я думал, что динамическое связывание является более гибким. «

Дополнительная информация: http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx

Кстати, цитата, которую я нашел там впоследствии:

Вы можете отметитьПараметр универсального типа является ковариантным, если он используется только в качестве возвращаемого типа метода и не используется в качестве типа параметров формального метода.И наоборот, вы можете пометить тип как контравариантный, если он используется только как тип параметров формального метода и не используется как тип возвращаемого метода.

0 голосов
/ 20 июня 2010

Единственное различие между вашими определениями Action и Func состоит в том, что Action не имеет возвращаемых типов.Если вы измените свой код с:

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

на

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

Это работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...