2011-05-26 50 views
2

我正在开发一个集合类,它应该实现IEnumerator和IEnumerable。实现集合的简单方法?

在我的第一种方法中,我直接实现了它们。现在我已经发现了yield关键字,并且我已经能够简化一切,用readonly属性代替IEnumerator/IEnumerable接口。使用yield的值在循环中返回IEnumerable。

我的问题:是否有可能使用yield,这样我就可以迭代类本身,而不实现IEnumerable/IEnumerator?

即,我希望有类似框架的集合一个功能:

List<int> myList = new List<int>(); 
foreach (int i in myList) 
{ 
    ... 
} 

这是可能的呢?

更新:看来我的问题措辞不妙。我不介意实现IEnumerator或IEnumerable;我只是认为唯一的方法就是使用旧的Current/MoveNext/Reset方法。

+0

我想不出任何理由,这将是一个好主意。我缺乏想象力吗? IEnumerator不是一个复杂或繁琐的界面。 – Jodrell 2011-05-26 09:05:12

+0

@Jodrell:让事情变得更简单并不是一个好主意?为什么? – raven 2011-05-26 09:23:51

+0

为什么你的收藏应该实现'IEnumerator '? – CodesInChaos 2011-05-26 09:23:55

回答

8

你不会实施IEnumerable<T>IEnumerable得到foreach工作 - 但它会是一个好主意,这样做。这是很容易做到:

public class Foo : IEnumerable<Bar> 
{ 
    public IEnumerator<Bar> GetEnumerator() 
    { 
     // Use yield return here, or 
     // just return Values.GetEnumerator() 
    } 

    // Explicit interface implementation for non-generic 
    // interface; delegates to generic implementation. 
    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

实现IEnumerable<T>只想打电话给你Values财产,但仍然提供了一个GetEnumerator()方法的选择:

public class Foo 
{ 
    public IEnumerator<Bar> GetEnumerator() 
    { 
     // Use yield return here, or 
     // just return Values.GetEnumerator() 
    } 
] 

虽然这工作,它意味着您将无法将您的收藏集传递给期望IEnumerable<T>的任何内容,例如LINQ to Objects。

这是一个鲜为人知的事实是foreach将与任何类型的支持GetEnumerator()方法,它返回适当MoveNext()Current成员类型的工作。这实际上是允许泛型之前的强类型集合,在集合上迭代不会包含值类型等。现在真的没有要求它,IMO。

+0

感谢您提供快速和完整的答案。出于某种原因,我认为yield只能用于返回IEnumerable。 – raven 2011-05-26 09:26:48

+0

@Jaime:如果你去http://manning.com/skeet,你仍然可以免费获得C#深度第一版的第6章。这一章是关于迭代器块:) – 2011-05-26 09:35:49

+0

@Jon Skeet,第8章看起来不错。 – Jodrell 2011-05-26 09:42:12

1

你可以做这样的事情,但为什么? IEnumerator已经很简单了。

Interface MyEnumerator<T> 
{ 
    public T GetNext(); 
} 

public static class MyEnumeratorExtender 
{ 
    public static void MyForeach<T>(this MyEnumerator<T> enumerator, 
     Action<T> action) 
    { 
     T item = enumerator.GetNext(); 
     while (item != null) 
     { 
      action.Invoke(item); 
      item = enumerator.GetNext(); 
     } 
    } 
} 

我宁愿有in关键字,我不想重写linq。

+0

对不起,误会。如上所述,我认为用yield来实现IEnumerator是不可能的,但现在我知道更好了,我不介意这样做:-) – raven 2011-05-26 11:54:51

相关问题