实现(可能)协变演员

时间:2017-11-15 15:12:57

标签: c# .net generics casting covariance

我有以下课程:

X : BaseX
XView : BaseView<X>
XDAO : BaseDAO<X>
MainViewModel<TX, TView, TDAO>
where TX : X
where TView : View<X>
where TDAO : DAO<X>
XMainViewModel : MainViewModel<X, XView, XDAO>

我有一个XMainViewModel<X, XView, XDAO>的实例。我想将其转换为MainViewModel<BaseX, BaseView<X>, BaseDAO<X>>。这可能吗?它可能涉及协变量。我不熟悉covariants,不久前才开始使用泛型,所以我在这里很困惑(我也希望我没有在问题中做任何拼写错误)。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:6)

  

这可能吗?

没有。仅使用引用类型构造的接口和委托支持通用协方差和逆变。

  

我在这里很困惑

这是一个令人困惑的话题。考虑它的一种方法是始终在问自己&#34;假设这是合法的;什么可能出错?&#34;你说

  

我有XMainViewModel<X, XView, XDAO>。我想将其转换为MainViewModel<BaseX, BaseView<X>, BaseDAO<X>>

让我们看一个更简单的例子。您有一个List<Giraffe>,并希望将其投放到List<Animal>。什么可能出错?

List<Giraffe> giraffes = new List<Giraffe>();
giraffes.Add(new Giraffe());
List<Animal> animals = (List<Animal>)giraffes; // This is illegal. What if it were legal?
animals.Add(new Tiger());
Giraffe g = giraffes[1]; // And we just put a Tiger into a variable of type Giraffe.

这就是为什么这是非法的,为什么你的例子也是非法的。但这是合法的:

IEnumerable<Animal> animals = giraffes;

为什么合法?因为 IEnumerable根本无法插入老虎。该接口已标记为协方差安全,并且C#编译器已验证它是安全的,因此允许此转换。

我已经写了很多关于协方差和逆变的SO答案以及博客文章和文章,所以如果你想了解更多关于这个功能以及为什么我们像我们那样设计它,请做一些搜索。

您可以通过(1)将MainViewModel<A, B, C>添加到接口并将其标记为IMainViewModel<out A, out B, out C>,然后(2)确保接口的任何方法都不需要A,B或C来使您的示例合法作为参数,A,B或C类型的属性都没有setter,依此类推。也就是说,A,B和C的每次使用都是输出位置,而不是输入位置。这就是编译器如何知道协方差是安全的。

  

我也希望我没有在问题中做任何拼写错误

它&#34;协方差&#34;而不是&#34;协变量&#34;。 &#34;协方差&#34;是名词; &#34;协变&#34;是一个形容词。