我有两个商业合同类:
public BusinessContract
public Person : BusinessContract
Run Code Online (Sandbox Code Playgroud)
在另一个类中,我有以下代码:
private Action<BusinessContract> _foo;
public void Foo<T>( Action<T> bar ) where T : BusinessContract
{
_foo = bar;
}
Run Code Online (Sandbox Code Playgroud)
以上甚至都不会编译,这让我感到困惑.我将T限制为BusinessContract,为什么编译器不知道bar可以分配给_foo?
为了解决这个问题,我们尝试将其更改为以下内容:
public void Foo<T>( Action<T> bar ) where T : BusinessContract
{
_foo = (Action<BusinessContract>)bar;
}
Run Code Online (Sandbox Code Playgroud)
现在编译器很高兴,所以我在我的应用程序的其他地方编写以下代码:
Foo<Person>( p => p.Name = "Joe" );
Run Code Online (Sandbox Code Playgroud)
应用程序在运行时以InvalidCastException爆炸.
我不明白.我不应该能够将更具体的类型转换为不太具体的类型并分配它吗?
UPDATE
Jon回答了这个问题,所以得到了点头,但只是为了关闭循环,这就是我们最终解决问题的方法.
private Action<BusinessContract> _foo;
public void Foo<T>( Action<T> bar ) where T : BusinessContract
{
_foo = contract => bar( (T)contract );
}
Run Code Online (Sandbox Code Playgroud)
我们为什么这样做?我们有一个假DAL,我们用于单元测试.使用其中一种方法,我们需要让测试开发人员能够指定在测试期间调用方法时应该执行的操作(这是一种从数据库更新缓存对象的刷新方法).Foo的目的是设置调用刷新时应该发生的事情.IOW,在本课程的其他地方,我们有以下内容.
public void Refresh( BusinessContract contract )
{
if( _foo != null )
{
_foo( contract );
}
}
Run Code Online (Sandbox Code Playgroud)
例如,测试开发人员可以决定在调用Refresh时将名称设置为不同的值.
Foo<Person>( p => p.Name = "New Name" );
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 18
你的协方差和逆变是错误的方式.让我们考虑Action<object>和Action<string>.删除实际的泛型,你试图做这样的事情:
private Action<object> _foo;
public void Foo(Action<string> bar)
{
// This won't compile...
_foo = bar;
}
Run Code Online (Sandbox Code Playgroud)
现在假设我们写:
_foo(new Button());
Run Code Online (Sandbox Code Playgroud)
那很好,因为Action<object>可以传递任何对象......但是我们用一个必须带字符串参数的委托来初始化它.哎哟.
这不是类型安全的,所以不编译.
另一种方法将工作,虽然:
private Action<string> _foo;
public void Foo(Action<object> bar)
{
// This is fine...
_foo = bar;
}
Run Code Online (Sandbox Code Playgroud)
现在当我们调用时_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
Run Code Online (Sandbox Code Playgroud)
目前还不清楚你要对这个动作做些什么,所以不幸的是我无法就如何解决这个问题给出任何建议......
| 归档时间: |
|
| 查看次数: |
1904 次 |
| 最近记录: |