C# 强制转换要列出的对象列表vs IList
刚刚遇到这个:C# 强制转换要列出的对象列表vs IList,c#,casting,C#,Casting,刚刚遇到这个: Func<List<object>> foo = () => new List<object>(); List<string> s = (List<string>)foo(); IList<string> s1 = (IList<string>)foo(); Func foo=()=>newlist(); List s=(List)foo(); IList s1=(IList)foo();
Func<List<object>> foo = () => new List<object>();
List<string> s = (List<string>)foo();
IList<string> s1 = (IList<string>)foo();
Func foo=()=>newlist();
List s=(List)foo();
IList s1=(IList)foo();
编译器抱怨强制转换到列表(有道理),但对IList却只字不提。让我想知道这是为什么?第一行在编译时失败,第二行在运行时出现“无法将'System.Collections.Generic.List
1[System.object]'类型的对象强制转换为'System.Collections.Generic.IList
1[System.String]'”异常
如果您看这个问题(),答案将阐明此编译工作的原因,并为满足提供的条件的类提供一个示例。编译器知道
列表不能是列表
因此,它给出了一个编译器错误
但是,如果列表
实际上是某个派生类,该派生类也实现了IList
,则第二次强制转换可能会成功
如果两种类型都不是接口,或者一种类型是不相关的接口,而另一种类型是密封的(或结构),则只能从转换中获得编译时错误
引用规范(§6.4.2)
显式引用转换为:
- 从对象和动态到任何其他引用类型
- 从任何类类型S到任何类类型T,只要S是T的基类
- 从任何类类型S到任何接口类型T,前提是S未密封且S未实现T。
- 从任何接口类型S到任何类类型T,前提是T未密封或T实现S。
- 从任何接口类型S到任何接口类型T,前提是S不是从T派生的
- [剪报]
(增加重点)
提供的…
子句排除了实际隐含的转换。已知为列表的对象可能实现IList
以及IList
,因此强制转换可能会成功。在这种情况下它不能,因为我们知道语句仅仅是<代码>新的表()/<代码>,但是编译器不这么认为。您可能已经扩展了列表
,并实现了另一个,例如
// not recommended, but second cast works
public class MyWeirdList : List<object>, IList<string>
//不推荐,但第二次强制转换有效
公共类MyWeirdList:List,IList
已知为列表
的对象不可能也是列表
,因为只能从单个类型继承
public class MyWeirdList : List<object>, List<string> // compiler error
公共类MyWeirdList:List,List//编译器错误
如果List
被密封,两个强制转换都将无效,因为这样编译器就可以确定类无法实现IList
。您可以改为使用此类来尝试此操作:
public sealed class SealedList<T> : List<T> { }
公共密封类密封列表:列表{}
我很确定最后一行在运行时会失败。确实会失败,但有趣的是编译器会捕获第一个案例。是的,会的。只是想知道它为什么会编译。@ReedCopsey,我应该声明我对编译器错误感兴趣。我同意;这很有趣。@ReedCopsey,编译器知道对列表
没有隐式强制转换操作,但是IList
的实现者可能能够?而另一种类型是密封的
?这是因为它知道它不能被继承者覆盖吗?@MichaelPerrenoud:justice.Hm,这使它成为一个有效的构造:Func foo=()=>new List();var s1=(IFoo)foo();“出乎意料,真的。”尤金:有时出乎意料,但必须是合法的。在过去的一周里,我已经在真实代码中不止一次这样做了。感谢您引用规范!