gpt4 book ai didi

c# - 为什么我不能使用数组的枚举器,而是自己实现?

转载 作者:IT王子 更新时间:2023-10-29 04:33:28 25 4
gpt4 key购买 nike

我有这样的代码:

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 ( );
}
}

但是编译器提示说:

"Cannot implicitly convert type 'System.Collections.IEnumerator' to 'System.Collections.Generic.IEnumerator'. An explicit conversion exists (are you missing a cast?)"

我认为 Array 类型实现了两个 IEnumerable 接口(interface),不是吗?因为我可以直接在 Values 实例上使用 Linq 功能。

最佳答案

这是一个微妙而有点不幸的事情。简单的解决方法是:

public IEnumerator<object> GetEnumerator ( )
{
return ((IEnumerable<object>)this.Values).GetEnumerator ( );
}

I thought the Array type implemented both IEnumerable interfaces, does it not?

规则是:

  • System.Array 使用公共(public)方法“隐式”实现 IEnumerable。
  • 每个数组类型 T[] 都继承自 System.Array。
  • 每个数组类型 T[] 实现 IList<T> , IEnumerable<T>等等。
  • 因此每个数组类型 T[] 都可以转换为 IEnumerable<T>

注意第三点不是

  • 每个数组类型 T[] 实现 IList<T> , IEnumerable<T>等等在隐式实现成员的 T[] 上定义的公共(public)方法和属性

好了。当您查找 GetEnumerator 时,我们在 object[] 上查找它并没有找到它,因为 object[] 实现了 IEnumerable<object> 明确地。它可转换IEnumerable<object> ,并且可转换性不计入查找。 (你不会期望“double”的方法出现在 int 上只是因为 int 可以转换为 double。)然后我们查看基本类型,发现 System.Array 使用公共(public)方法实现 IEnumerable,所以我们已经找到了我们的 GetEnumerator。

也就是这样想:

namespace System
{
abstract class Array : IEnumerable
{
public IEnumerator GetEnumerator() { ... }
...
}
}

class object[] : System.Array, IList<object>, IEnumerable<object>
{
IEnumerator<object> IEnumerable<object>.GetEnumerator() { ... }
int IList<object>.Count { get { ... } }
...
}

当您在 object[] 上调用 GetEnumerator 时,我们看不到作为显式接口(interface)实现的实现,因此我们转到基类,它确实有一个可见的。

How do all the object[], int[], string[], SomeType[] classes get generated "on the fly"?

魔法!

This is not generics, right?

没错。数组是非常特殊的类型,它们在 CLR 类型系统中有很深的层次。尽管它们在很多方面与泛型非常相似。

It seems like this class object [] : System.Array is something that can't be implemented by a user, right?

对,那只是为了说明如何思考它。

Which one do you think is better: Casting the GetEnumerator() to IEnumerable<object>, or just use foreach and yield?

问题的格式不正确。您不会将 GetEnumerator 转换为 IEnumerable<object> .您要么将数组 转换为IEnumerable<object>或者您将 GetEnumerator 转换为 IEnumerator<object> .

我可能会将值转换为 IEnumerable<object>并调用GetEnumerator在上面。

I will probably use casting but I am wondering if this is a place where you or some programmer who could read the code, would think it's less clear.

我认为类型转换很清楚。

when you said implicit implementation, you mean in the form of Interface.Method, right?

不,恰恰相反:

interface IFoo { void One(); void Two(); }
class C : IFoo
{
public void One() {} // implicitly implements IFoo.One
void IFoo.Two() {} // explicitly implements IFoo.Two
}

第一个声明默默地实现了方法。第二个是明确它实现了什么接口(interface)方法。

What's the reason for implementing IEnumerable<T> like that, instead of implicit implementation with public methods? I got curious because you said "This is a subtle and a bit unfortunate", so it seems like it's because of an older decision that forced you to do this I imagine?

我不知道是谁做的这个决定。但这有点不幸。它至少让一个用户——你——感到困惑,也让我在那里困惑了几分钟!

I would have thought the Array type would be something like this: public class Array<T> : IEnumerable<T> etc. But instead there is some magical code about it then, right?

没错。正如您昨天在问题中指出的那样,如果我们在 CLR v1 中使用泛型,情况就会大不相同。

数组本质上是一种通用的集合类型。因为它们是在没有泛型的类型系统中创建的,所以类型系统中必须有很多特殊代码来处理它们。

下次您设计类型系统时,将泛型放入 v1 中,并确保您从一开始就将强大的集合类型、可空类型和不可空类型融入到框架中。事后添加泛型和可为 null 的值类型很困难。

关于c# - 为什么我不能使用数组的枚举器,而是自己实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5110877/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com