Язык программирования C#9 и платформа .NET5
Определение анонимного типа
Анонимный тип определяется с использованием ключевого слова
r (см. главу 3) в сочетании с синтаксисом инициализации объектов (см. главу 5). Ключевое словоvaдолжно применяться из-за того, что компилятор будет автоматически генерировать новое определение класса на этапе компиляции (причем имя этого класса никогда не встретится в коде С#). Синтаксис инициализации применяется для сообщения компилятору о необходимости создания в новом типе закрытых поддерживающих полей и (допускающих только чтение) свойств.varВ целях иллюстрации создайте новый проект консольного приложения по имени
. Затем добавьте в классAnonymousTypesпоказанный ниже метод, который формирует новый тип на лету, используя данные входных параметров:Programstatic void BuildAnonymousType( string make, string color, int currSp ){// Построить анонимный тип с применением входных аргументов.var car = new { Make = make, Color = color, Speed = currSp };// Обратите внимание, что теперь этот тип можно// использовать для получения данных свойств!Console.WriteLine("You have a {0} {1} going {2} MPH",car.Color, car.Make, car.Speed);// Анонимные типы имеют специальные реализации каждого// виртуального метода System.Object. Например:Console.WriteLine("ToString() == {0}", car.ToString());}Обратите внимание, что помимо помещения кода внутрь функции анонимный тип можно также создавать непосредственно в строке:
Console.WriteLine("***** Fun with Anonymous Types *****\n");// Создать анонимный тип, представляющий автомобиль.var myCar = new { Color = "Bright Pink", Make = "Saab",CurrentSpeed = 55 };// Вывести на консоль цвет и производителя.Console.WriteLine("My car is a {0} {1}.", myCar.Color, myCar.Make);// Вызвать вспомогательный метод для построения// анонимного типа с указанием аргументов.BuildAnonymousType("BMW", "Black", 90);Console.ReadLine();В настоящий момент достаточно понимать, что анонимные типы позволяют быстро моделировать "форму" данных с небольшими накладными расходами. Они являются лишь способом построения на лету нового типа данных, который поддерживает базовую инкапсуляцию через свойства и действует в соответствии с семантикой на основе значений. Чтобы уловить суть последнего утверждения, давайте посмотрим, каким образом компилятор C# строит анонимные типы на этапе компиляции, и в особенности — как он переопределяет члены
.System.ObjectВнутреннее представление анонимных типов
Все анонимные типы автоматически наследуются от
и потому поддерживают все члены, предоставленные этим базовым классом. В результате можно вызывать методSystem.Object,ToString(),GetHashCode()илиEquals()на неявно типизированном объектеGetType(). Предположим, что в классеmyCarопределен следующий статический вспомогательный метод:Programstatic void ReflectOverAnonymousType(object obj){Console.WriteLine("obj is an instance of: {0}",obj.GetType().Name);Console.WriteLine("Base class of {0} is {1}",obj.GetType().Name, obj.GetType().BaseType);Console.WriteLine("obj.ToString() == {0}", obj.ToString());Console.WriteLine("obj.GetHashCode() == {0}",obj.GetHashCode());Console.WriteLine();}Пусть вы вызвали метод
, передав ему объектReflectOverAnonymousType()в качестве параметра:myCarConsole.WriteLine("***** Fun with Anonymous Types *****\n");// Создать анонимный тип, представляющий автомобиль.var myCar = new {Color = "Bright Pink", Make = "Saab",CurrentSpeed = 55};// Выполнить рефлексию того, что сгенерировал компилятор.ReflectOverAnonymousType(myCar);...Console.ReadLine();Вывод будет выглядеть примерно так:
***** Fun with Anonymous Types *****obj is an instance of: <>f__AnonymousType0`3Base class of <>f__AnonymousType0`3 is System.Objectobj.ToString() = { Color = Bright Pink, Make = Saab, CurrentSpeed = 55 }obj.GetHashCode() = -564053045Первым делом обратите внимание в примере на то, что объект
имеет типmyCar(в вашем выводе имя типа может быть другим). Помните, что имя, назначаемое типу, полностью определяется компилятором и не доступно в коде C# напрямую.<>f__AnonymousType0`3Пожалуй, наиболее важно здесь то, что каждая пара "имя-значение", определенная с использованием синтаксиса инициализации объектов, отображается на идентично именованное свойство, доступное только для чтения, и соответствующее закрытое поддерживающее поле, которое допускает только инициализацию. Приведенный ниже код C# приблизительно отражает сгенерированный компилятором класс, применяемый для представления объекта
(его можно просмотреть посредством утилитыmyCar):ildasm.exe