我有两个业务合同类别:
public BusinessContract
public Person : BusinessContract在另一个类中,我有以下代码:
private Action<BusinessContract> _foo;
public void Foo<T>( Action<T> bar ) where T : BusinessContract
{
_foo = bar;
}上面的代码甚至不能编译,这让我有点困惑。我将T约束为BusinessContract,那么为什么编译器不知道可以将bar赋值给_foo呢?
为了解决这个问题,我们尝试将其更改为以下内容:
public void Foo<T>( Action<T> bar ) where T : BusinessContract
{
_foo = (Action<BusinessContract>)bar;
}现在编译器很高兴了,所以我在应用程序的其他地方编写了以下代码:
Foo<Person>( p => p.Name = "Joe" );这个应用程序在运行时会出现一个InvalidCastException。
我还是不明白。难道我不能将更具体的类型转换为不太具体的类型并赋值给它吗?
更新
Jon回答了这个问题,所以得到了同意,但为了结束这个循环,我们最终解决了这个问题。
private Action<BusinessContract> _foo;
public void Foo<T>( Action<T> bar ) where T : BusinessContract
{
_foo = contract => bar( (T)contract );
}我们为什么要这么做?我们有一个用于单元测试的假DAL。对于其中一个方法,我们需要让测试开发人员能够指定该方法在测试期间被调用时应该做什么(它是一个更新数据库中缓存对象的刷新方法)。Foo的目的是设置在调用刷新时应该发生什么。在这个类的其他地方,我们有以下内容。
public void Refresh( BusinessContract contract )
{
if( _foo != null )
{
_foo( contract );
}
}例如,测试开发人员可以在调用Refresh时决定将名称设置为不同的值。
Foo<Person>( p => p.Name = "New Name" );发布于 2011-08-02 05:44:36
你把协方差和逆方差弄错了。让我们考虑一下Action<object>和Action<string>。删除实际的泛型后,您将尝试执行以下操作:
private Action<object> _foo;
public void Foo(Action<string> bar)
{
// This won't compile...
_foo = bar;
}现在假设我们这样写:
_foo(new Button());这很好,因为Action<object>可以传递给任何对象...但是我们已经用一个委托初始化了它,这个委托必须接受一个字符串参数。唉哟。
这不是类型安全的,所以不能编译。
不过,另一种方式也是可行的:
private Action<string> _foo;
public void Foo(Action<object> bar)
{
// This is fine...
_foo = bar;
}现在,当我们调用_foo时,我们必须传入一个字符串--但这很好,因为我们已经用一个可以接受任何object引用作为参数的委托对它进行了初始化,所以我们恰好给它一个字符串也没什么问题。
因此,基本上Action<T>是逆变的,而Func<T>是协变的
Func<string> bar = ...;
Func<object> foo = bar; // This is fine
object x = foo(); // This is guaranteed to be okay不清楚你想做什么,所以不幸的是,我真的不能给出任何关于如何解决这个问题的建议……
发布于 2011-08-02 05:44:24
它不能被赋值,因为由于您使用的是逆变量而不是协变量,所以无法保证泛型类型可以被赋值给foo。
https://stackoverflow.com/questions/6904805
复制相似问题