Как работает 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]: Я забыл включить "Показывать код, сгенерированный компилятором", поэтому я не понял, как это работает.
Ответы
Ответ 1
Чтобы добавить код к решению HuorSwords, компилятор будет генерировать метод ToString
для вашего примера, как показано ниже:
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("{ Test = ");
stringBuilder.Append((object) this.<Test>__Field);
stringBuilder.Append(", Integer = ");
stringBuilder.Append((object) this.<Integer>__Field);
stringBuilder.Append(", s = ");
stringBuilder.Append((object) this.<s>__Field);
stringBuilder.Append(" }");
return ((object) stringBuilder).ToString();
}
Было бы неэффективно использовать производительность здесь, когда у вас есть все необходимые метаданные во время компиляции.
Декомпилировавшись с помощью dotPeek, эта версия может отличаться в зависимости от используемого декомпилятора.
Примечание: как вы также декомпилировали с помощью dotPeek, попробуйте посмотреть на пространство имен корней. Там вы найдете нечто похожее на:
[DebuggerDisplay("\\{ Test = {Test}, Integer = {Integer}, s = {s} }", Type = "<Anonymous Type>")]
internal sealed class <>__AnonymousType0<<Test>
Это пример того, что компилируется при создании анонимных объектов.
Ответ 2
С анонимными объектами...
Компилятор создает внутренний закрытый класс, который моделирует анонимный тип. Анонимный тип неизменен; все свойства только для чтения. Этот класс содержит переопределения Equals() и GetHashCode(), которые реализуют семантику значений. В дополнение компилятор генерирует переопределение ToString(), которое отображает значение каждой публичной собственности.
Источник: ссылка
Пожалуйста, проверьте @Ilya Ivanov ответ, чтобы увидеть код по этому вопросу.
Ответ 3
Анонимные типы все еще полностью определены типами... просто: компилятор генерирует их полностью самостоятельно, и вы никогда не увидите имя/реализацию (просто: оно соответствует инициализатору, который вы используете в своем коде).
Фактически, ToString
не упоминается в отношении анонимных типов в конкретном деле (раздел 7.6.10.6); требуется только, чтобы Equals
и GetHashCode
работали по свойствам. В примере в спецификации ( "объявляет анонимный тип формы" ) не включает переопределение ToString
.
Компилятор MS добавляет реализацию ToString
на основе свойств в качестве притязания, но также, возможно, потому, что по умолчанию ToString
- это имя типа, которое само по себе было бы бессмысленным (это, в конце концов, анонимное - имя типа довольно ужасно для чтения и включает синтаксис генериков). Честно говоря, было бы неплохо использовать это только для целей отладки.