Анонимные типы
Анонимные типы позволяют легко инкапсулировать свойства только для чтения в один объект без необходимости предварительного определения типа. Имя типа создается компилятором и недоступно на уровне исходного кода. Тип каждого свойства выводится компилятором.
Анонимные типы создаются с помощью new
оператора вместе с инициализатором объектов. Дополнительные сведения об инициализаторах объектов см. в статье Инициализаторы объектов и коллекций.
В следующем примере показан анонимный тип, инициализированный с помощью двух свойств — Amount
и Message
.
var v = new { Amount = 108, Message = "Hello" };
// Rest the mouse pointer over v.Amount and v.Message in the following
// statement to verify that their inferred types are int and string.
Console.WriteLine(v.Amount + v.Message);
Анонимные типы обычно используются в select
предложении выражения запроса для возврата подмножества свойств из каждого объекта в исходной последовательности. Дополнительные сведения о запросах см. в разделе о LINQ в C#.
Анонимные типы содержат один или несколько публичных свойств только для чтения. Другие члены класса, например методы или события, недопустимы. Выражение, которое используется для инициализации свойства, не может быть null
, анонимной функцией или типом указателя.
Наиболее частый сценарий — это инициализация анонимного типа со свойствами из другого типа. В следующем примере предполагается, что существует класс с именем Product
. Класс Product
включает Color
и Price
свойства вместе с другими свойствами, которые вам не нужны:
class Product
{
public string? Color {get;set;}
public decimal Price {get;set;}
public string? Name {get;set;}
public string? Category {get;set;}
public string? Size {get;set;}
}
Объявление анонимного типа запускается с помощью ключевого слова new
. Объявление инициализирует новый тип, который использует только два свойства из Product
. Использование анонимных типов приводит к тому, что в запросе возвращается меньший объем данных.
Если имена членов в анонимном типе не указаны, компилятор предоставляет членам анонимного типа то же имя, что и свойство, используемое для инициализации. Укажите имя свойства, инициализируемого выражением, как показано в предыдущем примере. В следующем примере используются имена свойств анонимного типа Color
и Price
. Экземпляры являются элементами Product
из products
коллекции типов:
var productQuery =
from prod in products
select new { prod.Color, prod.Price };
foreach (var v in productQuery)
{
Console.WriteLine("Color={0}, Price={1}", v.Color, v.Price);
}
Совет
Правило стиля .NET можно использовать IDE0037 для принудительного применения выводимых или явных имен элементов.
Также можно определить поле по объекту другого типа: класс, структуру или даже другой анонимный тип. Это делается с помощью переменной, удерживающей этот объект так же, как в следующем примере, где создаются два анонимных типа с использованием уже созданных пользователем типов. В обоих случаях product
поле в анонимном типе shipment
и shipmentWithBonus
будет иметь тип Product
, содержащий значения по умолчанию каждого поля. bonus
И поле будет иметь анонимный тип, созданный компилятором.
var product = new Product();
var bonus = new { note = "You won!" };
var shipment = new { address = "Nowhere St.", product };
var shipmentWithBonus = new { address = "Somewhere St.", product, bonus };
Обычно, если для инициализации переменной используется анонимный тип, необходимо обозначить ее как неявно типизированную переменную с помощью ключевого слова var. Имя типа не может быть указано в объявлении переменной, так как доступ к базовому имени анонимного типа имеет только компилятор. Дополнительные сведения о var
см. в разделе Неявно типизированные локальные переменные.
Вы можете создать массив анонимно типизированных элементов, объединив неявно типизированные локальные переменные и неявно типизированный массив, как показано в следующем примере.
var anonArray = new[] { new { name = "apple", diam = 4 }, new { name = "grape", diam = 1 }};
Анонимные типы являются class
типами, производными непосредственно от object
, и которые нельзя привести к любому типу, кроме object
. Компилятор назначает имя для каждого анонимного типа, несмотря на то что для вашего приложения оно недоступно. С точки зрения среды CLR анонимный тип не отличается от других ссылочных типов.
Если два или несколько инициализаторов анонимных объектов в сборке указывают на последовательность свойств, идущих в том же порядке и имеющих те же типы и имена, компилятор обрабатывает объекты как экземпляры одного типа. Они используют одни и те же сведения типа, созданные компилятором.
Анонимные типы поддерживают неразрушительную мутацию в виде выражений. Это позволяет создать новый экземпляр анонимного типа, где одно или несколько свойств имеют новые значения:
var apple = new { Item = "apples", Price = 1.35 };
var onSale = apple with { Price = 0.79 };
Console.WriteLine(apple);
Console.WriteLine(onSale);
Никакое поле, свойство, событие или тип возвращаемого значения метода невозможно объявить, используя анонимный тип. Точно так же нельзя объявить с помощью анонимного типа ни один формальный параметр метода, свойства, конструктора или индексатора. Чтобы передать анонимный тип или коллекцию, содержащую анонимные типы, в качестве аргумента в метод, можно объявить параметр как тип object
. Однако использование object
для анонимных типов побеждает цель строгого ввода. Если вам нужно сохранить результаты запроса или передать их за пределы метода, используйте вместо анонимного типа структуру или класс, названные обычным образом.
Так как методы Equals и GetHashCode в анонимных типах определяются через методы Equals
и GetHashCode
свойств, два экземпляра одного и того же анонимного типа равны, только если равны их свойства.
Примечание.
Уровень доступности анонимного типа , internal
поэтому два анонимных типа, определенных в разных сборках, не имеют одного типа.
Таким образом, экземпляры анонимных типов не могут быть равны друг другу при определении в разных сборках, даже если все их свойства равны.
Анонимные типы переопределяют ToString метод, сцепляя имя и ToString
выходные данные каждого свойства, окруженного фигурными скобками.
var v = new { Title = "Hello", Age = 24 };
Console.WriteLine(v.ToString()); // "{ Title = Hello, Age = 24 }"