【问题标题】:Question About IEnumerable<T>关于 IEnumerable<T> 的问题
【发布时间】:2010-07-06 19:56:19
【问题描述】:

我注意到 IEnumerable (Generics) 需要实现 2 个方法:

1. IEnumerator&lt;T&gt; GetEnumerator()

2。 IEnumerable.GetEnumerator()方法

(http://msdn.microsoft.com/en-us/library/19e6zeyy.aspx)

什么是#2,我应该如何定义/实现

从我玩弄一些代码来看,似乎 IEnumerator GetEnumerator() 在 foreach 循环中被调用。 #2 IEnumerable.GetEnumerator 在哪里发挥作用?

我正在阅读 Oreilly 的 C# 3.0 Cookbook 中的配方 6.1 在泛型类型上创建迭代器,但由于未实现 #2(它未包含在配方代码中)而出现错误。

谢谢!

【问题讨论】:

标签: c# c#-3.0


【解决方案1】:

第一个是泛型​​ GetEnumerator,而第二个是非泛型。它们在功能上做相同的工作,但非泛型只能返回 object 类型。

实现这些最简单的方法是实现泛型版本,然后为非泛型提供:

IEnumerator IEnumerable.GetEnumerator() {
   return GetEnumerator();
}

【讨论】:

    【解决方案2】:

    非泛型 IEnumerable 接口用于向后兼容,也为以非泛型方式访问泛型 IEnumerable 接口提供了非常有用的功能。

    您可以只实现 IEnumerable.GetEnumerator 成员,而只是显式实现其他接口,如

    IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); /*generic method call*/ }
    

    【讨论】:

      【解决方案3】:

      #2 是来自IEnumerable 接口的GetEnumerator 方法的显式 非泛型实现。 #1 在您的示例中是 GetEnumerator() 的实现 IEnumerable&lt;T&gt; 接口。

      IEnumerable.GetEnumerator() 可以调用与 IEnumerable 相同的底层代码,只是它不是强类型的(返回对象而不是强类型的 IEnumerator)。

      【讨论】:

        【解决方案4】:

        你只需要定义一个泛型(在我的例子中返回 String),然后告诉非泛型 GetEnumerator 方法调用泛型 GetEnumerator(返回 Object)。

        class Foo : IEnumerable<string>
        {
            public IEnumerator<string> GetEnumerator()
            {
                foreach (string value in new[] { "a", "b", "c" })
                {
                    yield return value;
                }
            }
        
            IEnumerator IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }
        }
        

        【讨论】:

          【解决方案5】:

          第二个是为.NET v1.1编写的代码,它不理解泛型。

          通常,您只需让它从通用 GetEnumerator() 中返回值

          IEnumerator IEnumerable.GetEnumerator()
          {
               return GetEnumerator();
          }
          

          【讨论】:

            【解决方案6】:

            要实现第二个接口,请执行一个显式实现,它简单地调用通用接口的隐式实现。像

            class FooCollection : IEnumerable<Foo>, IEnumerable
            {
                IEnumerator IEnumerable.GetEnumerator()
                {
                    return GetEnumerator();
                }
            
                public IEnumerator<Foo> GetEnumerator()
                {
                    // return enumerator
                }
            }
            

            编辑:IEnumerable 继承是多余的,但这个答案表明,当你继承IEnumerable&lt;T&gt; 时,这两个接口都将被实现,因为IEnumerable&lt;T&gt; 派生自IEnumerable

            【讨论】:

            • @x0n,这部分是一个好点,我的代码在接口继承声明部分是多余的,但它确实显示了正在发生的事情。实现泛型接口需要实现非泛型接口。不过,准确地说,IEnumerable&lt;T&gt; 并没有实现 IEnumerable。不能。
            • 我并不想让你回想起来——一个简单的评论就足够了。我会扭转它。更新:除非您编辑问题以修复冗余,否则我无法反转分数;-)
            • 是的,“实施”是错误的动词。 “源自”或“继承”就是我的意思。呵呵。
            【解决方案7】:

            通常您不再需要自己实现 IEnumerable。框架中有许多内置类实现了这个接口,以各种不同的方式来满足你 99% 的需求。

            但是,如果您愿意,IEnumerable,GetEnumerator() 方法会将 IEnumerator 对象返回给调用 foreach 的客户端 此 Ienumerator 对象是跟踪集合中哪个元素是“下一个”的对象" 当 foreach "迭代" 时返回一个。为此,您必须定义一个类,该类将是 Enumerator(它必须实现 IEnumerator,或通常为 IEnumerator)

            作为一个例子(对于 PersonCollection)

            public IEnumerator GetEnumerator() { return new myTypeEnumerator(this); }
            public class myTypeEnumerator : IEnumerator
            {
                int nIndex;
                PersonCollection pers;
                public myTypeEnumerator(PersonCollection myTypes) 
                 { pers = myTypes; nIndex = -1; }
                public bool MoveNext() { return (++nIndex < pers.alPers.Count); }
                public object Current { get { return (pers[nIndex]); } }
                public void Reset() { nIndex = -1; }
            }
            

            这个和泛型版本的唯一区别是泛型版本是强类型的:

            public IEnumerator<T> GetEnumerator() { return new myTypeEnumerator<T>(this); }
            public class myTypeEnumerator<T> : IEnumerator<T>
            {
                int nIndex;
                IList<T> tList;
                public myTypeEnumerator(IList<T> listOfTs) 
                 { 
                    tList = listOfTs; 
                    nIndex = -1; 
                 }
                public bool MoveNext() { return (++nIndex < tList.Count); }
                public T Current { get { return (tList[nIndex]); } }
                public void Reset() { nIndex = -1; }
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-03-28
              相关资源
              最近更新 更多