Nev*_*ing 4 c# ienumerable foreach
我对foreach行为有疑问C#.
我的自定义类实现了自定义GetEnumerator.此方法返回另一个object可隐式转换为的方法string.
但是,如果我foreach(string s in customClass)在运行时失败("无法将类型的对象转换为字符串").
但是,如果我这样做string x = new B()就像一个魅力.
注意:我没有必要在这里实现任何目标,我只是想了解发生了什么.我对这种非通用行为特别感兴趣.
有任何想法吗?我错过了哪些基础知识?
代码复制这个:
public class A : IEnumerable
{
#region IEnumerable Members
public IEnumerator GetEnumerator()
{
yield return new B();
}
#endregion
}
public class B
{
public static implicit operator string( B b )
{
return "to-stringed implicit";
}
}
// CODE:
A a = new A();
// Works.
B b = new B();
string xxx = b;
// Doesnt work.
foreach( string str in a )
{
}
Run Code Online (Sandbox Code Playgroud)
只有在编译器看到它可以在编译时使用时,才能使用隐式转换:
B b = new B();
string str = b;
Run Code Online (Sandbox Code Playgroud)
它不能在运行时使用:
B b = new B();
object obj = b;
string str = obj; // will fail at run-time
Run Code Online (Sandbox Code Playgroud)
基本上,这是因为它是通过看远太昂贵所有可能的转换,从obj一个string可能的工作.(参见Eric Lippert博客文章).
您的IEnumerator返回对象,因此调用foreach (string str in a)尝试在运行时将其转换object为a B.
var e = a.GetEnumerator();
e.MoveNext();
object o = e.Current;
string str = o; // will fail at run-time
Run Code Online (Sandbox Code Playgroud)
如果改为使用foreach(B item in a) { string str = item; ... },运行时转换为object以B(其中工程,因为每个对象是一个B),并将其从转换B到str可以被进行编译.
var e = a.GetEnumerator();
e.MoveNext();
object o = e.Current;
B item = o; // will work at run-time because o _is_ a B
string str = item; // conversion made by the compiler
Run Code Online (Sandbox Code Playgroud)
解决这个问题的另一种方法是制作A工具IEnumerable<B>而不仅仅是IEnumerable.然后,foreach (string str in a)翻译为
var e = a.GetEnumerator();
e.MoveNext();
B b = e.Current; // not object!
string str = b; // conversion made by the compiler
Run Code Online (Sandbox Code Playgroud)
所以编译器可以在不必更改foreach循环的情况下进行转换.
foreach方法不需要您实现IEnumerable.所需要的只是你的类有一个叫做的方法GetEnumerator:
public class A
{
public IEnumerator GetEnumerator()
{
yield return new B();
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以在一个foreach:
A a = new A();
foreach (B str in a)
{
Console.WriteLine(str.GetType());
}
Run Code Online (Sandbox Code Playgroud)
但是foreach语句不会调用隐式运算符.您必须手动执行此操作:
foreach (B item in a)
{
string str = item;
// use the str variable here
}
Run Code Online (Sandbox Code Playgroud)