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>不能。谢谢。

4

3 回答 3

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.
于 2010-06-20T18:45:20.070 回答
0

Action 和 Func 定义之间的唯一区别是 Action 没有返回类型。如果您从以下位置更改代码:

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

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

有用。

于 2010-06-20T12:45:41.180 回答
0

好,我知道了。

动作定义如下:delegate void Action <in T> (T arg);,而func是这样delegate TResult Func <in T, out TResult> (T arg);的: 问题出在out关键字上,表示协变,而不是in关键字的逆变。同时typeof(dynamic) == typeof(object)也是真的。所以dynamic,作为一种更通用的类型,与我们所采用的任何东西都不是协变的。嗯,我觉得动态绑定更灵活。”</p>

进一步阅读:http: //blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx

顺便说一句,我后来在那里找到的报价:

如果泛型类型参数仅用作方法返回类型而不用作形式方法参数的类型,则可以将其标记为协变。反之亦然,如果一个类型仅用作形式方法参数的类型而不用作方法返回类型,则可以将其标记为逆变。

于 2010-06-21T05:31:31.933 回答