.NET4:如何将动态绑定应用于带返回的匿名委托?

发布于 2024-09-06 04:25:10 字数 1787 浏览 8 评论 0原文

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→ Action 可以,而 Func则可以→ Func 不是。谢谢。

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

Why does it work for actions and doesn't for functions?
In other words, I just would like to know why Action<dynamic> → Action<string> is ok while Func<dynamic,dynamic> → Func<string, int> is not. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

情栀口红 2024-09-13 04:25:14

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

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

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

它就可以了。

The only difference between your Action and Func definitions is Action has no return types. If you change your code from:

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

to

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

It works.

冰之心 2024-09-13 04:25:14

好的,我明白了。

该操作定义如下:delegate void Action; (T arg);,而 func 是这样的: delegate TResult Func; (T arg); 问题出在 out 关键字中,它表示协变,但不像 in 关键字那样表示逆变。同时 typeof(dynamic) == typeof(object) 为 true。因此,动态作为一种更通用的类型,与我们所采用的任何内容都不协变。嗯,我认为动态绑定更灵活。“

进一步阅读:链接

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

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

Ok, I got it.

The action is defined as follows: delegate void Action <in T> (T arg);, while the func is like this: delegate TResult Func <in T, out TResult> (T arg); The problem is in out keyword, which indicates covariance but not contravariance as in keyword does. At the same time typeof(dynamic) == typeof(object) is true. So dynamic, as a more general type, isn't covariant to whatever we take. Hmm, I thought dynamic binding is more flexible.“

Further reading: Link

Btw, the quote I found there afterwards:

You can mark a generic type parameter as covariant if it is used only as a method return type and is not used as a type of formal method parameters.
And vice versa, you can mark a type as contravariant if it is used only as a type of formal method parameters and not used as a method return type.

℉絮湮 2024-09-13 04:25:13

如果 C# 需要返回类型为 int 的委托,则声明返回 dynamic 的委托是不兼容的。您的委托被声明为 Func,并且 C# 是强类型的。它并不关心你的函数是否实际上返回一个 int 并接受一个字符串;它仍然被声明为Func

如果您考虑以下示例,代码无法编译的原因是显而易见的:

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.

If C# is expecting a delegate with a return type of int, a delegate declared to return dynamic is incompatible. Your delegate is declared as Func<dynamic, dynamic>, and C# is strongly-typed. It doesn't care if your function actually returns an int and takes a string; it's still declared as Func<dynamic, dynamic>.

The reason why the code doesn't compile is obvious if you consider this example:

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.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文