实现(可能)协变投射



我有以下类:

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>>。这可能吗?它可能涉及协变。我不熟悉协变,不久前才开始使用泛型,所以我在这里很困惑(我也希望我在这个问题上没有错别字)。感谢您的帮助。

这可能吗?

否。通用协方差和逆变差仅在使用引用类型构造的接口和委托上受支持。

我在这里很困惑

这是一个令人困惑的话题。思考它的一种方法是总是问自己"假设这是合法的;会出什么问题?"你说

我有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的每次使用都是输出位置,而不是输入的位置。这就是编译器如何知道它对协方差是安全的。

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

这是"协方差",而不是"协变量"。"协方差"是一个名词;"协变"是一个形容词。

相关内容

  • 没有找到相关文章

最新更新