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节); 只需要 Equals
和GetHashCode
在属性方面起作用。 规范中的示例(“声明表单的匿名类型”)不包括ToString
覆盖。
MS编译器添加了一个基于属性的ToString
实现作为一个礼貌 – 但也许是因为默认的 ToString
是类型名称,这本身就没有意义(毕竟,它是匿名的 – 类型名称读起来非常糟糕) ,并包括generics语法)。 坦率地说,仅将此用于调试目的是个好主意。