为什么我不能使用数组的枚举器,而不是自己实现它?
我有一些像这样的代码:
public class EffectValues : IEnumerable { public object [ ] Values { get; set; } public IEnumerator GetEnumerator ( ) { return this.Values.GetEnumerator ( ); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ( ) { return this.GetEnumerator ( ); } }
但编译器抱怨说:
“无法将类型’System.Collections.IEnumerator’隐式转换为’System.Collections.Generic.IEnumerator’。存在显式转换(您是否错过了转换?)”
我以为Array类型实现了IEnumerable接口,不是吗? 因为我可以直接在Values实例上使用Linqfunction。
这是一个微妙的,有点不幸。 简单的解决方法是:
public IEnumerator
我以为Array类型实现了IEnumerable接口,不是吗?
规则是:
- System.Array使用公共方法“隐式”实现IEnumerable。
- 每个数组类型T []都inheritance自System.Array。
- 每个数组类型T []实现
IList
,IEnumerable
等。 - 因此每个数组类型T []都可以转换为
IEnumerable
请注意,第三点不是
- 每个数组类型T []实现
IList
,IEnumerable
等等, 在T []上定义的公共方法和属性隐式实现成员
你去吧 当你查找GetEnumerator时,我们在object []上查找并找不到它,因为object [] 显式地实现了IEnumerable
。 它可以转换为IEnumerable
,并且convertiable不计入查找。 (你不会期望在int上出现“double”方法只是因为int可以转换为double。)然后我们查看基类型,发现System.Array使用公共方法实现IEnumerable,所以我们已经找到了我们的GetEnumerator。
也就是说,想想这样:
namespace System { abstract class Array : IEnumerable { public IEnumerator GetEnumerator() { ... } ... } } class object[] : System.Array, IList, IEnumerable { IEnumerator IEnumerable.GetEnumerator() { ... } int IList.Count { get { ... } } ... }
当你在object []上调用GetEnumerator时,我们看不到实现是一个显式的接口实现,所以我们转到基类,它有一个可见的。
如何“动态”生成所有object [],int [],string [],SomeType []类?
魔法!
这不是generics,对吧?
对。 数组是非常特殊的类型,它们可以深入到CLR类型系统中。 虽然它们在许多方面与generics非常相似。
看起来这个
class object [] : System.Array
是用户无法实现的东西,对吧?
对,这只是为了说明如何思考它。
您认为哪一个更好:将
GetEnumerator()
为IEnumerable
,或者只使用foreach
和yield
?
问题是形象不对称。 您不会将GetEnumerator强制转换为IEnumerable
。 您可以将数组转换为IEnumerable
也可以将GetEnumerator转换为IEnumerator
。
我可能会将值转换为IEnumerable
并在其上调用GetEnumerator
。
我可能会使用转换,但我想知道这是否是你或某些程序员可以阅读代码的地方,会认为它不太清楚。
我认为演员阵容非常清楚。
当你说隐式实现时,你的意思是Interface.Method的forms,对吧?
不,相反:
interface IFoo { void One(); void Two(); } class C : IFoo { public void One() {} // implicitly implements IFoo.One void IFoo.Two() {} // explicitly implements IFoo.Two }
第一个声明默默地实现该方法。 第二个是明确它实现的接口方法。
实现
IEnumerable
的原因是什么,而不是公共方法的隐式实现? 我很好奇,因为你说“这是一个微妙而有点不幸”,所以看起来这是因为一个较老的决定迫使你做我想象的事情?
我不知道是谁做出了这个决定。 不过有点不幸。 它至少让一个用户感到困惑 – 你 – 它也让我困惑了几分钟!
我原本认为Array类型是这样的:
public class Array
等。但是有一些神奇的代码呢,对吧?: IEnumerable
对。 正如你在昨天的问题中所指出的那样,如果我们在CLR v1中使用generics,事情会有很大的不同。
数组本质上是一种通用的集合类型。 因为它们是在没有generics的类型系统中创建的,所以类型系统中必须有许多特殊代码来处理它们。
下次设计一个类型系统时,将generics置于v1中并确保获得强大的集合类型,从一开始就将可空类型和非可空类型烘焙到框架中。 事后添加generics和可空值类型很困难。
您必须将数组转换为IEnumerable
才能访问通用枚举器:
public IEnumerator GetEnumerator() { return ((IEnumerable)this.Values).GetEnumerator(); }