foreach如何将对象转换为指定的类型? [英] How does foreach casts objects to specified types?
问题描述
在 C#
中有一个关于 foreach
行为的问题。
我的自定义类实现了一个自定义 GetEnumerator
。此方法返回可隐式转换为 string
的另一个对象
。
然而,如果我做了
foreach(customClass中的字符串s)
它在运行时失败(无法将类型的对象转换为字符串)。但是,如果我做了 string x = new B()
,它就像一个魅力一样。 $ b
注意:这里没有什么特别的我需要实现,我只是想知道发生了什么。我特别感兴趣的是非 -generic行为。
有什么想法?我缺少什么基础知识?
代码复制:
pre $ $ code > public class A:IEnumerable
{
#region IEnumerable成员
public IEnumerator GetEnumerator()
{
yield return new B();
}
#endregion
}
公共类B
{
公共静态隐式运算符字符串(B b)
{
返回to-stringed implicit;
}
}
//代码:
A a = new A();
//工作。
B b = new B();
string xxx = b;
//不工作。
foreach(a中的字符串str)
{
}
您的隐式转换只能在编译器认为可以在编译时使用的情况下使用:
B b = new B();
string str = b;
运行时无法使用:
B b = new B();
object obj = b;
string str = obj; //在运行时会失败
基本上,这是因为看起来太贵通过 all 从 obj
转换为字符串
可能的工作。 (请参阅 Eric Lippert博客文章) / p>
您的 IEnumerator
返回对象,所以调用 foreach(string str in a)
试图将一个对象
转换为一个 B
var e = a.GetEnumerator();
e.MoveNext();
对象o = e.Current;
string str = o; //在运行时会失败
如果改用 foreach(B项目在a){字符串str =项目; ...}运行时转换是从
object
到 B
因为每个对象是 B
),并且从 B
转换为<$ c
$ b
var 可以编译$ c> str
e = a.GetEnumerator();
e.MoveNext();
对象o = e.Current;
B item = o; //将在运行时工作,因为o _is_ a B
string str = item; //编译器进行的转换
解决这个问题的方法是使 A
实现 IEnumerable
,而不仅仅是 IEnumerable
。然后, foreach(字符串str中的a)
转换更多作为
var e = a.GetEnumerator();
e.MoveNext();
B b = e.Current; //不反对!
string str = b; //编译器所做的转换
所以编译器可以进行转换,而不必更改 foreach
循环。
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:
B b = new B();
string str = b;
It can't be used at run-time:
B b = new B();
object obj = b;
string str = obj; // will fail at run-time
Basically, this is because it would be far too expensive to look through all the possible conversions from obj
to a string
that might work. (See this Eric Lippert blog post).
Your IEnumerator
returns objects, so calling foreach (string str in a)
is trying to convert an object
to a B
at runtime.
var e = a.GetEnumerator();
e.MoveNext();
object o = e.Current;
string str = o; // will fail at run-time
If you instead use foreach(B item in a) { string str = item; ... }
, the runtime conversion is from object
to B
(which works, because each object is a B
), and the conversion from B
to str
can be made by the compiler.
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
A different way to fix this would be to make A
implement IEnumerable<B>
instead of just IEnumerable
. Then, foreach (string str in a)
translates more as
var e = a.GetEnumerator();
e.MoveNext();
B b = e.Current; // not object!
string str = b; // conversion made by the compiler
so the compiler can make the conversion without you having to change your foreach
loop.
这篇关于foreach如何将对象转换为指定的类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!