C#学习教程:Class是否需要实现IEnumerable才能使用Foreach分享


Class是否需要实现IEnumerable才能使用Foreach

这是在C#中,我有一个类,我从其他人的DLL使用。 它没有实现IEnumerable,但有2个传递IEnumerator的方法。 有没有办法可以在这些上使用foreach循环。 我正在使用的课程是密封的。

与流行的看法相反, foreach不需要IEnumerable 。 它需要的是一个方法GetEnumerator ,它返回任何具有方法MoveNext对象和具有相应签名的get-property Current

/编辑:但是,在你的情况下,你运气不好。 但是,您可以简单地包装您的对象,以使其可枚举:

 class EnumerableWrapper { private readonly TheObjectType obj; public EnumerableWrapper(TheObjectType obj) { this.obj = obj; } public IEnumerator GetEnumerator() { return obj.TheMethodReturningTheIEnumerator(); } } // Called like this: foreach (var xyz in new EnumerableWrapper(yourObj)) …; 

/编辑:如果方法返回IEnumerator ,由几个人提出的以下方法不起作用:

 foreach (var yz in yourObj.MethodA()) …; 

Re:如果foreach不需要显式接口契约,它是否使用reflection找到GetEnumerator?

(我不能评论,因为我没有足够高的声誉。)

如果你暗示运行时reflection,那么没有。 它完成所有编译时间,另一个鲜为人知的事实是它还检查可能实现IEnumerator的返回对象是否是一次性的。

要查看此操作,请考虑此(可运行)代码段。

 using System; using System.Collections.Generic; using System.Text; namespace ConsoleApplication3 { class FakeIterator { int _count; public FakeIterator(int count) { _count = count; } public string Current { get { return "Hello World!"; } } public bool MoveNext() { if(_count-- > 0) return true; return false; } } class FakeCollection { public FakeIterator GetEnumerator() { return new FakeIterator(3); } } class Program { static void Main(string[] args) { foreach (string value in new FakeCollection()) Console.WriteLine(value); } } } 

根据MSDN :

 foreach (type identifier in expression) statement 

表达式是:

对象集合或数组表达式。 集合元素的类型必须可转换为标识符类型。 不要使用计算结果为null的表达式。 计算实现IEnumerable的类型或声明GetEnumerator方法的类型。 在后一种情况下,GetEnumerator应返回实现IEnumerator的类型或声明IEnumerator中定义的所有方法。

简短回答:

您需要一个名为GetEnumerator的方法的类,它返回您已有的IEnumerator。 使用简单的包装器实现此目的:

 class ForeachWrapper { private IEnumerator _enumerator; public ForeachWrapper(Func enumerator) { _enumerator = enumerator; } public IEnumerator GetEnumerator() { return _enumerator(); } } 

用法:

 foreach (var element in new ForeachWrapper(x => myClass.MyEnumerator())) { ... } 

来自C#语言规范 :

foreach语句的编译时处理首先确定表达式的集合类型,枚举器类型和元素类型。 该决定如下:

  • 否则,检查可枚举的接口:

  • 不严格。 只要该类具有所需的GetEnumerator,MoveNext,Reset和Current成员,它将与foreach一起使用

    不,你没有,你甚至不需要GetEnumerator方法,例如:

     class Counter { public IEnumerable Count(int max) { int i = 0; while (i <= max) { yield return i; i++; } yield break; } } 

    这是这样称呼的:

     Counter cnt = new Counter(); foreach (var i in cnt.Count(6)) { Console.WriteLine(i); } 

    你总是可以把它包起来,并且作为一个“可以接近”的你可以只需要一个带有正确签名的名为“GetEnumerator”的方法。

     class EnumerableAdapter { ExternalSillyClass _target; public EnumerableAdapter(ExternalSillyClass target) { _target = target; } public IEnumerable GetEnumerator(){ return _target.SomeMethodThatGivesAnEnumerator(); } } 

    给定类X和方法A和B都返回IEnumerable,你可以在类上使用foreach,如下所示:

     foreach (object y in XA()) { //... } // or foreach (object y in XB()) { //... } 

    据推测,A和B返回的可枚举的含义是明确的。

    @Brian:不确定你是否尝试遍历方法调用或类本身的值返回,如果你想要的是类,那么通过使它成为一个可以与foreach一起使用的数组。

    对于一个可以与foeach一起使用的类,它需要做的就是有一个返回的公共方法和名为GetEnumerator()的IEnumerator,就是这样:

    采取以下类,它不实现IEnumerable或IEnumerator:

     public class Foo { private int[] _someInts = { 1, 2, 3, 4, 5, 6 }; public IEnumerator GetEnumerator() { foreach (var item in _someInts) { yield return item; } } } 

    或者可以编写GetEnumerator()方法:

      public IEnumerator GetEnumerator() { return _someInts.GetEnumerator(); } 

    在foreach中使用时(注意,使用了无包装器,只是一个类实例):

      foreach (int item in new Foo()) { Console.Write("{0,2}",item); } 

    打印:

    1 2 3 4 5 6

    该类型仅需要具有名为GetEnumerator的公共/非静态/非generics/无参数方法,该方法应返回具有公共MoveNext方法和公共Current属性的内容。 正如我在某处回忆Eric Lippert先生所做的那样, 这是为了在价值类型的情况下适应类型安全和拳击相关性能问题的预先通用时代。

    例如,这有效:

     class Test { public SomethingEnumerator GetEnumerator() { } } class SomethingEnumerator { public Something Current //could return anything { get { } } public bool MoveNext() { } } //now you can call foreach (Something thing in new Test()) //type safe { } 

    然后由编译器将其翻译为:

     var enumerator = new Test().GetEnumerator(); try { Something element; //pre C# 5 while (enumerator.MoveNext()) { Something element; //post C# 5 element = (Something)enumerator.Current; //the cast! statement; } } finally { IDisposable disposable = enumerator as System.IDisposable; if (disposable != null) disposable.Dispose(); } 

    从规格的8.8.4节。


    值得注意的是所涉及的枚举器优先级 – 就像你有一个public GetEnumerator方法一样,那么这是foreach的默认选择,无论是谁实现它。 例如:

     class Test : IEnumerable { public SomethingEnumerator GetEnumerator() { //this one is called } IEnumerator IEnumerable.GetEnumerator() { } } 

    如果您没有公共实现(即只有显式实现),那么优先级就像IEnumerator >> IEnumerator

    上述就是C#学习教程:Class是否需要实现IEnumerable才能使用Foreach分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—猴子技术宅(www.ssfiction.com)

    本文来自网络收集,不代表猴子技术宅立场,如涉及侵权请点击右边联系管理员删除。

    如若转载,请注明出处:https://www.ssfiction.com/ckf/960139.html

    发表评论

    邮箱地址不会被公开。 必填项已用*标注