查看此代码:
public class myWords : IEnumerable<string>
{
string[] f = "I love you".Split(new string[]{"lo"},StringSplitOptions.RemoveEmptyEntries);
public IEnumerator<string> GetEnumerator()
{
return f.Select(s => s + "2").GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return f.Select(s => s + "3").GetEnumerator();
}
}
跑步:
myWords m = new myWords();
foreach (var s in m)
{
Console.WriteLine(s);
}
产量
I 2
ve you2 // notice "2", so the generic Ienumerator has executed.
我了解非通用IEnumerator
版本是为了兼容性。
问题:
IEnumerator
一起运行?答案 0 :(得分:7)
只要代码将类强制转换为非泛型接口,就会执行非泛型IEnumerator:
((IEnumerable)myWords).GetEnumerator(); // this calls the non-generic one
如果您将类传递给需要非通用IEnumerator的遗留函数,则这一点非常重要。
因此,如果您有一个包含函数的库并且您将类传递给此函数,那么它将使用非泛型IEnumerator
DoSomeStuffWithAnIEnumerable(IEnumerable x)
{
var foo = x.GetEnumerator();
// or, as stackx said, an example with foreach:
foreach (var foo2 in x)
Console.WriteLine(foo2);
}
DoSomeStuffWithAnIEnumerable(new myWords());
请注意,使用通用的IEnumerator简单地实现非通用IEnumerator是完全有效的:
public class myWords : IEnumerable<string>
{
....
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
这样你可以确定它们都具有相同的效果。
答案 1 :(得分:4)
IEnumerable
的非泛型版本是使用显式接口实现实现的。这意味着您只能通过强制转换到接口来调用显式实现的函数。
明确实现IEnumerable
的原因是方法签名除了返回类型之外是相同的。
将myWords
明确地投射到IEnumerable
,您可以调用非通用版本,如下所示:(IEnumerable)myWords
。
C#指南解释了其工作原理:Explicit interface implementation。
答案 2 :(得分:4)
其他答案有点错过了重点。
如果foreach
ed的(编译时)类型有一个名为public
的{{1}}非泛型非静态方法,则接口无关紧要参数。 (此方法的返回类型可以是任何类型,通用或非泛型:接口无关紧要。)
因此调用第一个方法的原因是这是GetEnumerator
方法。
您可以更改:
public
要证明不需要接口,请尝试以下方法:
public class myWords : IEnumerable<string>
{
string[] f = "I love you".Split(new string[]{"lo"},StringSplitOptions.RemoveEmptyEntries);
IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
return f.Select(s => s + "2").GetEnumerator();
}
public IEnumerator GetEnumerator()
{
return f.Select(s => s + "3").GetEnumerator();
}
}
但是,实施public class myWords // no interfaces!
{
string[] f = "I love you".Split(new string[]{"lo"},StringSplitOptions.RemoveEmptyEntries);
public IEnumerator GetEnumerator()
{
return f.Select(s => s + "3").GetEnumerator();
}
}
是明智之举。然后您的类型可以与Linq一起使用(IEnumerable<>
上的扩展方法),并且可以用作仅需要IEnumerable<>
的其他方法的参数。
此外,使用返回非泛型IEnumerable<>
的方法(或显式接口实现)只调用返回IEnumerator
的方法(或显式接口实现)是明智的。让两个返回不同的序列真的令人困惑(但很好地询问和回答关于事情如何工作的问题)。