foreach如何将对象转换为指定的类型? [英] How does foreach casts objects to specified types?

查看:401
本文介绍了foreach如何将对象转换为指定的类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆