对于类似的类型:
CoolCollection<T>
你可以:
foreach (T item in coolCollection)
{
...
}
foreach (CoolNode node in coolCollection)
{
...
}
如果这不可能,可能像foreach2,或其他一些迭代方式。很多时候,我真的想要一种迭代类型的方法。
编辑:对不起,如果不清楚的话。基本上CoolNode是一个生成CoolCollection的节点。 CoolNode有一个名为value的属性来返回T,但是我需要另一个迭代器才能返回CoolNodes。EDIT2:我不能做coolCollection.Something迭代,因为CoolNodes通过一个名为Next的属性连接,就像LinkedList一样。所以我需要实现2个迭代器。
答案 0 :(得分:3)
只需让CoolCollection<T>
明确实施IEnumerable<CoolNode<T>>
以及IEnumerable<T>
。 (我猜它真的是CoolNode<T>
,但如果没有,只要把额外的<T>
带到各地。)
这将允许您以两种方式进行迭代,尽管您需要演员。
要做到这一点,你需要这样的东西:
class CoolCollection<T> : ICollection<T>, IEnumerable<CoolNode<T>>
{
IEnumerator<CoolNode<T>> IEnumerable<CoolNode<T>>.GetEnumerator()
{
///...Do work here...
}
IEnumerator<T> GetEnumerator()
{
///...Do work here...
}
}
使用它就像这样:
foreach (T item in coolCollection)
{
...
}
foreach (CoolNode<T> node in (IEnumerable<CoolNode<T>>)coolCollection)
{
...
}
另一种选择是公开“节点”的属性,所以你可以这样做:
foreach(var nodes in coolCollection.Nodes)
{ ... }
要实现这一点,你会改变一些事情。你需要创建一个实现枚举器的私有类......类似于:
class CoolCollection<T> : ICollection<T>
{
private List<CoolNode<T>> nodes;
IEnumerable<CoolNode<T>> Nodes
{
get
{
foreach(var node in this.nodes) { yield return node; }
}
}
}
答案 1 :(得分:2)
如果我正确理解了这个问题......
你可以这样做,与其他一些集合对象类似:
例如:
foreach (int key in IDictionary.Keys)
{
}
foreach (object value in IDictionary.Values)
{
}
但我认为没有办法按照你所写的方式做到......
答案 2 :(得分:1)
不,你不能这样做。您不能重载默认迭代器。
想象一下,如果你可以重载你的默认迭代器。
这会怎么做? foreach (object o in foo)
,没有合理的方法来选择合适的迭代器。
你可以做的是有另一个名为ForEach2的方法,它以不同的方式遍历你的集合。或者您可以显式实现接口。或者你可以使用Linq组合来做这种事情。
从课堂设计的角度来看:
interface IBar {
IEnumerator<string> GetEnumerator();
}
class Foo : IBar, IEnumerable<int> {
// Very bad, risky code. Enumerator implementations, should
// line up in your class design.
public IEnumerator<int> GetEnumerator()
{
yield return 1;
yield return 2;
yield return 3;
yield return 4;
}
IEnumerator<string> IBar.GetEnumerator()
{
yield return "hello";
}
// must be IEnumerable if you want to support foreach
public IEnumerable<string> AnotherIterator
{
get {
yield return "hello2";
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
EachPair的LINQ扩展
struct Pair<T> {
public T First;
public T Second;
}
static class LinqExtension {
public static IEnumerable<Pair<T>> EachPair<T>(this IEnumerable<T> input) {
T first = default(T);
bool gotFirst = false;
foreach (var item in input)
{
if (!gotFirst)
{
first = item;
gotFirst = true;
}
else {
yield return new Pair<T>() { First = first, Second = item };
gotFirst = false;
}
}
}
}
测试代码:
class Program
{
static void Main(string[] args)
{
var foo = new Foo();
foreach (int number in foo)
{
Console.WriteLine(number);
}
// LINQ composition - a good trick where you want
// another way to iterate through the same data
foreach (var pair in foo.EachPair())
{
Console.WriteLine("got pair {0} {1}", pair.First, pair.Second);
}
// This is a bad and dangerous practice.
// All default enumerators should be the same, otherwise
// people will get confused.
foreach (string str in (IBar)foo)
{
Console.WriteLine(str);
}
// Another possible way, which can be used to iterate through
// a portion of your collection eg. Dictionary.Keys
foreach (string str in foo.AnotherIterator)
{
Console.WriteLine(str);
}
}
答案 3 :(得分:0)
如果CoolCollection实现IEnumerable,你可以写:
foreach (var item in coolCollection)
{
...
}
或者如果T是CoolNode
foreach (CoolNode node in coolCollection)
{
...
}
如果您需要以某种方式将每个项目转换为您的类型,您可以使用Linq Select运算符:
foreach (CoolNode node in coolCollection.Select(item => ConvertToNode(item))
{
...
}
答案 4 :(得分:0)
查看iterindex
代码段。在您的班级中,输入iterindex
并点击[TAB]
。它将帮助您实现“命名迭代器和索引器”模式。
结果可以像这样使用:
foreach (var e in myTree.DepthFirstView) // supports iteration
{
if (e == myTree.DepthFirstView[2]) // supports indexing
{
// ...
}
}
(我写了这个片段,但我怀疑它从来没有得到很好的使用。永远。)