为什么我不能使用数组的枚举器,而是自己实现它?
我有一些这样的代码:
public class EffectValues : IEnumerable<object>
{
public object [ ] Values { get; set; }
public IEnumerator<object> 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 实例上使用 Linq 功能。
I have some code like this:
public class EffectValues : IEnumerable<object>
{
public object [ ] Values { get; set; }
public IEnumerator<object> GetEnumerator ( )
{
return this.Values.GetEnumerator ( );
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ( )
{
return this.GetEnumerator ( );
}
}
But the compiler complains saying:
"Cannot implicitly convert type
'System.Collections.IEnumerator' to
'System.Collections.Generic.IEnumerator'.
An explicit conversion exists (are you
missing a cast?)"
I thought the Array type implemented both IEnumerable interfaces, does it not? Because I can use Linq features on the Values instance directly.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是一个微妙且有点不幸的事情。简单的解决方法是:
规则是:
IList
、IEnumerable
等。IEnumerable
请注意,第三点不是
IList
,IEnumerable
等在 T[] 上定义隐式实现成员的公共方法和属性就这样。当您查找 GetEnumerator 时,我们会在 object[] 上查找它,但没有找到它,因为 object[] 显式实现了
IEnumerable
也就是说,这样想:
当您在 object[] 上调用 GetEnumerator 时,我们看不到作为显式接口实现的实现,因此我们转到基类,它确实有一个可见的。
魔法!
正确的。数组是非常特殊的类型,它们深深地融入到 CLR 类型系统中。尽管它们在很多方面与泛型非常相似。
是的,这只是为了说明如何思考。
这个问题的格式不正确。您无需将 GetEnumerator 强制转换为
IEnumerable。您可以将数组强制转换为
IEnumerable,或者将GetEnumerator强制转换为
IEnumerator。
我可能会将 Values 转换为 IEnumerable并对其调用
GetEnumerator
。我认为演员阵容很清楚。
不,相反:
第一个声明默默实现该方法。第二个是关于它实现的接口方法的明确。
我不知道是谁做出了这个决定。但这有点不幸。它至少让一个用户——你——感到困惑,也让我困惑了几分钟!
正确的。正如您昨天在问题中指出的那样,如果我们在 CLR v1 中使用泛型,情况将会有很大不同。
数组本质上是一种通用集合类型。因为它们是在没有泛型的类型系统中创建的,所以类型系统中必须有大量特殊代码来处理它们。
下次设计类型系统时,将泛型放入 v1 中,并确保从一开始就将强集合类型、可空类型和不可空类型嵌入到框架中。事后添加泛型和可为 null 的值类型很困难。
This is a subtle and a bit unfortunate. The easy workaround is:
The rules are:
IList<T>
,IEnumerable<T>
and so on.IEnumerable<T>
Notice that the third point was NOT
IList<T>
,IEnumerable<T>
and so on with public methods and properties defined on T[] that implicitly implement the membersAnd there you go. When you look up GetEnumerator, we look it up on object[] and don't find it, because object[] implements
IEnumerable<object>
explicitly. It is convertible toIEnumerable<object>
, and convertibility doesn't count for lookups. (You wouldn't expect a method of "double" to appear on int just because int is convertible to double.) We then look at the base type, and find that System.Array implements IEnumerable with a public method, so we've found our GetEnumerator.That is, think about it like this:
When you call GetEnumerator on object[], we don't see the implementation that is an explicit interface implementation, so we go to the base class, which does have one visible.
Magic!
Right. Arrays are very special types and they are baked in at a deep level into the CLR type system. Though they are very similar to generics in a lot of ways.
Right, that was just to illustrate how to think about it.
The question is ill-formed. You don't cast the GetEnumerator to
IEnumerable<object>
. You either cast the array toIEnumerable<object>
or you cast the GetEnumerator toIEnumerator<object>
.I would probably cast Values to
IEnumerable<object>
and callGetEnumerator
on it.I think it's pretty clear with the cast.
No, the opposite:
The first declaration silently implements the method. The second is explicit about what interface method it implements.
I don't know who made this decision. It is kind of unfortunate though. It's confused at least one user -- you -- and it confused me for a few minutes there too!
Right. As you noted in your question yesterday, things would have been a lot different if we'd had generics in CLR v1.
Arrays are essentially a generic collection type. Because they were created in a type system that did not have generics, there has to be lots of special code in the type system to handle them.
Next time you design a type system put generics in v1 and make sure you get strong collection types, nullable types and non-nullable types baked in to the framework from the beginning. Adding generics and nullable value types post hoc was difficult.
您必须将数组转换为
IEnumerable才能访问通用枚举器:
You have to cast the array to
IEnumerable<object>
to be able to access the generic enumerator: