ToString如何在匿名类型上工作?

我正在搞乱匿名类型,我不小心将它输出到控制台上。 它看起来基本上是我如何定义它。

这是一个重现它的简短程序:

using System; class Program { public static void Main(string[] args) { int Integer = 2; DateTime DateTime = DateTime.Now; Console.WriteLine(new { Test = 0, Integer, s = DateTime }); Console.ReadKey(true); } } 

现在,输出是:

 { Test = 0, Integer = 2, s = 28/05/2013 15:07:19 } 

我尝试使用dotPeek进入程序集找出原因,但没有任何帮助。 [1]这是dotPeek’d代码:

 // Type: Program // Assembly: MyProjectName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null // Assembly location: Not telling you! :P using System; internal class Program { public static void Main(string[] args) { Console.WriteLine((object) new { Test = 0, Integer = 2, s = DateTime.Now }); Console.ReadKey(true); } } 

所以没有太大的不同。

那么它是怎样工作的? 它如何输出呢?

笔记:

[1] :我忘了打开“显示编译器生成的代码”,这就是我没有得到它如何工作的原因。

只是为HuorSwords答案添加一些代码,编译器将为您的示例生成 ToString方法,如下所示:

 public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("{ Test = "); stringBuilder.Append((object) this.__Field); stringBuilder.Append(", Integer = "); stringBuilder.Append((object) this.__Field); stringBuilder.Append(", s = "); stringBuilder.Append((object) this.__Field); stringBuilder.Append(" }"); return ((object) stringBuilder).ToString(); } 

当您在编译时拥有所有必需的元数据时,在此处使用reflection将是性能效率低下的。

使用dotPeek进行反编译,此版本可能会因使用的反编译器而异。

注意:由于您还使用dotPeek进行反编译,请尝试查看根命名空间 。 在那里你会发现类似的东西:

 [DebuggerDisplay("\\{ Test = {Test}, Integer = {Integer}, s = {s} }", Type = "")] internal sealed class <>__AnonymousType0< 

这是编译匿名对象时编译生成的示例。

使用匿名对象……

编译器生成一个内部密封类,用于对匿名类型进行建模。 匿名类型是不可变的; 所有属性都是只读的。 该类包含实现值语义的Equals()和GetHashCode()的重写。 此外,编译器生成ToString()的覆盖,显示每个公共属性的值。

来源: 链接

请检查@Ilya Ivanov的答案,看看有关此主题的一些代码。

匿名类型仍然是完全定义的类型……简单地说:编译器完全自己生成它们,你永远不会看到名称/实现(只是:它匹配你在代码中使用的初始化程序)。

实际上,关于特定操作中的匿名类型, 没有提到 ToString (第7.6.10.6节); 只需要 EqualsGetHashCode在属性方面起作用。 规范中的示例(“声明表单的匿名类型”)不包括ToString覆盖。

MS编译器添加了一个基于属性的ToString实现作为一个礼貌 – 但也许是因为默认的 ToString是类型名称,这本身就没有意义(毕竟,它是匿名的 – 类型名称读起来非常糟糕) ,并包括generics语法)。 坦率地说,仅将此用于调试目的是个好主意。