I have a question about foreach behavior in C#.
My custom class implements a custom GetEnumerator. This method returns another object that is implicitly convertible to string.
However if I do foreach(string s in customClass) it fails during run-time (“Unable to cast object of type .. to string”).
However if I do string x = new B() it works like a charm.
NOTE: There is nothing in particular I need to achieve here, I just want to understand what is going on. I am particularly interested in this non-generic behavior.
Any ideas? What fundamental knowledge am I missing?
Code to replicate this:
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 )
{
}
Your implicit conversion can only be used if the compiler sees it can be used at compile-time:
It can’t be used at run-time:
Basically, this is because it would be far too expensive to look through all the possible conversions from
objto astringthat might work. (See this Eric Lippert blog post).Your
IEnumeratorreturns objects, so callingforeach (string str in a)is trying to convert anobjectto aBat runtime.If you instead use
foreach(B item in a) { string str = item; ... }, the runtime conversion is fromobjecttoB(which works, because each object is aB), and the conversion fromBtostrcan be made by the compiler.A different way to fix this would be to make
AimplementIEnumerable<B>instead of justIEnumerable. Then,foreach (string str in a)translates more asso the compiler can make the conversion without you having to change your
foreachloop.