且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

动作委托、泛型、协变和逆变

更新时间:2022-12-16 08:36:09

你把协变和逆变弄错了.让我们考虑 Action<object>Action<string>.删除实际的泛型,您正在尝试执行以下操作:

You've got the covariance and contravariance the wrong way round. Let's consider Action<object> and Action<string>. Removing the actual generics, you're trying to do something like this:

private Action<object> _foo;

public void Foo(Action<string> bar)
{
    // This won't compile...
    _foo = bar;
}

现在假设我们接着写:

_foo(new Button());

这很好,因为 Action<object> 可以被传递 any 对象...但是我们已经用一个 必须 的委托对其进行了初始化> 接受一个字符串参数.哎哟.

That's fine, because Action<object> can be passed any object... but we've initialized it with a delegate which must take a string argument. Ouch.

这不是类型安全的,因此无法编译.

This isn't type safe, so doesn't compile.

不过, 的另一种方式也可以:

The other way would work though:

private Action<string> _foo;

public void Foo(Action<object> bar)
{
    // This is fine...
    _foo = bar;
}

现在当我们调用 _foo 时,我们必须 传入一个字符串 - 但这很好,因为我们已经用一个可以接受任何 object 引用作为参数,所以我们可以给它一个字符串.

Now when we invoke _foo, we have to pass in a string - but that's fine, because we've initialized it with a delegate which can take any object reference as a parameter, so it's fine that we happen to be giving it a string.

所以基本上 Action<T>逆变 - 而 Func协变:

So basically Action<T> is contravariant - whereas Func<T> is covariant:

Func<string> bar = ...;
Func<object> foo = bar; // This is fine
object x = foo(); // This is guaranteed to be okay

不清楚你想用这个动作做什么,所以很遗憾,我无法就如何解决这个问题提供任何建议......

It's not clear what you're trying to do with the action, so unfortunately I can't really give any advice on how to get around this...