[英]Why can't I pass IList<ChildType> to F(IEnumerable<ParentType>)?
[英]Why can I cast the invariance of IList<T> away?
目前,我正准备为我的同事介绍C#中新的通用差异功能。 为了简化故事,我写了以下几行:
IList<Form> formsList = new List<Form> { new Form(), new Form() };
IList<Control> controlsList = formsList;
是的,这当然是不可能的,因为IList(Of T)是不变的(至少我的想法)。 编译器告诉我:
无法将
System.Collections.Generic.IList<System.Windows.Forms.Form>
类型隐式转换为System.Collections.Generic.IList<System.Windows.Forms.Control>
。 存在显式转换(您是否错过了演员?)
嗯,这是否意味着我可以强制进行显式转换? 我刚尝试过:
IList<Form> formsList = new List<Form> { new Form(), new Form() };
IList<Control> controlsList = (IList<Control>)formsList;
并且...它编译! 这是否意味着我可以抛弃不变性? - 至少编译器没问题,但我只是将前编译时错误转为运行时错误:
Unable to cast object of type 'System.Collections.Generic.List`1[System.Windows.Forms.Form]' to type 'System.Collections.Generic.IList`1[System.Windows.Forms.Control]'.
我的问题:为什么我可以将IList<T>
(或我的实验的任何其他不变界面)的不变性抛弃了? 我是否真的抛弃了不变性,或者这里发生了什么样的转换(因为IList(Of Form)
和IList(Of Control)
是完全不相关的)? 这是C#的一个黑暗角落,我不知道?
从本质上讲,类型可以实现IList<Control>
以及 IList<Form>
因此转换成功是可能的 - 因此编译器暂时允许它(除此之外:它可能在这里更聪明并产生警告,因为它知道引用对象的具体类型,但不知道。我不认为产生编译器错误是合适的,因为它不是实现新接口的类型的重大变化)。
作为这种类型的一个例子:
public class EvilList : IList<Form>, IList<Control> { ... }
在运行时发生的只是CLR类型检查。 您看到的例外情况表示此操作失败。
为演员生成的IL是:
castclass [mscorlib]System.Collections.Generic.IList`1<class [System.Windows.Forms]System.Windows.Forms.Control>
来自MSDN :
castclass指令尝试将堆栈顶部的对象引用(类型O)强制转换为指定的类。 新类由指示所需类的元数据标记指定。 如果堆栈顶部的对象类没有实现新类(假设新类是接口)并且不是新类的派生类,则抛出InvalidCastException。 如果对象引用是空引用,则castclass成功并将新对象作为空引用返回。
如果无法将obj强制转换为类,则抛出InvalidCastException。
我怀疑在这种情况下,如果您尝试将新的TextBlock添加到controlsList中,则会抛出运行时异常。 TextBlock将符合controlsList的合同,但不符合formsList。
IList<Form> formsList = new List<Form> { new Form(), new Form() };
IList<Control> controlsList = (IList<Control>)formsList;
controlsList.Add(New TextBlock); // Should throw at runtime.
在这种情况下,类型安全不变通常会将其作为运行时异常。 在这种情况下,您可以安全地将controlsList声明为IEnumerable而不是IList(假设.Net 4.0),因为IEnumerable被声明为协变(IEnumerable)。 这解决了尝试向控件列表添加错误类型的问题,因为.add(和其他输入方法)在out接口中不可用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.