Подтвердить что ты не робот

Как работает 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]: Я забыл включить "Показывать код, сгенерированный компилятором", поэтому я не понял, как это работает.

4b9b3361

Ответ 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 - это имя типа, которое само по себе было бы бессмысленным (это, в конце концов, анонимное - имя типа довольно ужасно для чтения и включает синтаксис генериков). Честно говоря, было бы неплохо использовать это только для целей отладки.