首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >动作委托、泛型、协变和逆变

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

Stack Overflow用户
提问于 2011-08-02 05:41:13
回答 2查看 2.2K关注 0票数 10

我有两个业务合同类别:

代码语言:javascript
复制
public BusinessContract

public Person : BusinessContract

在另一个类中,我有以下代码:

代码语言:javascript
复制
private Action<BusinessContract> _foo;

public void Foo<T>( Action<T> bar ) where T : BusinessContract
{
    _foo = bar;
}

上面的代码甚至不能编译,这让我有点困惑。我将T约束为BusinessContract,那么为什么编译器不知道可以将bar赋值给_foo呢?

为了解决这个问题,我们尝试将其更改为以下内容:

代码语言:javascript
复制
public void Foo<T>( Action<T> bar ) where T : BusinessContract
{
    _foo = (Action<BusinessContract>)bar;
}

现在编译器很高兴了,所以我在应用程序的其他地方编写了以下代码:

代码语言:javascript
复制
Foo<Person>( p => p.Name = "Joe" );

这个应用程序在运行时会出现一个InvalidCastException。

我还是不明白。难道我不能将更具体的类型转换为不太具体的类型并赋值给它吗?

更新

Jon回答了这个问题,所以得到了同意,但为了结束这个循环,我们最终解决了这个问题。

代码语言:javascript
复制
private Action<BusinessContract> _foo;

public void Foo<T>( Action<T> bar ) where T : BusinessContract
{
    _foo = contract => bar( (T)contract );
}

我们为什么要这么做?我们有一个用于单元测试的假DAL。对于其中一个方法,我们需要让测试开发人员能够指定该方法在测试期间被调用时应该做什么(它是一个更新数据库中缓存对象的刷新方法)。Foo的目的是设置在调用刷新时应该发生什么。在这个类的其他地方,我们有以下内容。

代码语言:javascript
复制
public void Refresh( BusinessContract contract )
{
    if( _foo != null )
    {
        _foo( contract );
    }
}

例如,测试开发人员可以在调用Refresh时决定将名称设置为不同的值。

代码语言:javascript
复制
Foo<Person>( p => p.Name = "New Name" );
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-08-02 05:44:36

你把协方差和逆方差弄错了。让我们考虑一下Action<object>Action<string>。删除实际的泛型后,您将尝试执行以下操作:

代码语言:javascript
复制
private Action<object> _foo;

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

现在假设我们这样写:

代码语言:javascript
复制
_foo(new Button());

这很好,因为Action<object>可以传递给任何对象...但是我们已经用一个委托初始化了它,这个委托必须接受一个字符串参数。唉哟。

这不是类型安全的,所以不能编译。

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

代码语言:javascript
复制
private Action<string> _foo;

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

现在,当我们调用_foo时,我们必须传入一个字符串--但这很好,因为我们已经用一个可以接受任何object引用作为参数的委托对它进行了初始化,所以我们恰好给它一个字符串也没什么问题。

因此,基本上Action<T>是逆变的,而Func<T>是协变的

代码语言:javascript
复制
Func<string> bar = ...;
Func<object> foo = bar; // This is fine
object x = foo(); // This is guaranteed to be okay

不清楚你想做什么,所以不幸的是,我真的不能给出任何关于如何解决这个问题的建议……

票数 19
EN

Stack Overflow用户

发布于 2011-08-02 05:44:24

它不能被赋值,因为由于您使用的是逆变量而不是协变量,所以无法保证泛型类型可以被赋值给foo。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6904805

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档