Чтение онлайн

ЖАНРЫ

Язык программирования C#9 и платформа .NET5
Шрифт:

class SomeClass

{

// Определить набор закрытых переменных-членов...

// Создать свойство для каждой закрытой переменной-члена...

// Переопределить метод ToStringO для учета основных

// переменных-членов...

// Переопределить методы GetHashCode и Equals для работы

// с эквивалентностью на основе значений...

}

Как

видите, задача не обязательно оказывается настолько простой. Вам потребуется не только написать большой объем кода, но еще и сопровождать дополнительный класс в системе. Для временных данных подобного рода было бы удобно формировать специальный тип на лету. Например, пусть необходимо построить специальный метод, который принимает какой-то набор входных параметров.Такие параметры нужно использовать для создания нового типа данных, который будет применяться внутри области действия метода. Вдобавок желательно иметь возможность быстрого вывода данных с помощью метода
ToString
и работы с другими членами
System.Object
. Всего сказанного можно достичь с помощью синтаксиса анонимных типов.

Определение анонимного типа

Анонимный тип определяется с использованием ключевого слова

va
r (см. главу 3) в сочетании с синтаксисом инициализации объектов (см. главу 5). Ключевое слово
var
должно применяться из-за того, что компилятор будет автоматически генерировать новое определение класса на этапе компиляции (причем имя этого класса никогда не встретится в коде С#). Синтаксис инициализации применяется для сообщения компилятору о необходимости создания в новом типе закрытых поддерживающих полей и (допускающих только чтение) свойств.

В целях иллюстрации создайте новый проект консольного приложения по имени

AnonymousTypes
. Затем добавьте в класс
Program
показанный ниже метод, который формирует новый тип на лету, используя данные входных параметров:

static 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
. Предположим, что в классе
Program
определен следующий статический вспомогательный метод:

static 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
, передав ему объект
myCar
в качестве параметра:

Console.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`3

Base class of <>f__AnonymousType0`3 is System.Object

obj.ToString = { Color = Bright Pink, Make = Saab, CurrentSpeed = 55 }

Поделиться с друзьями: