Typy anonimowe

Typy anonimowe zapewniają wygodny sposób hermetyzacji zestawu właściwości tylko do odczytu w jednym obiekcie bez konieczności jawnego definiowania typu. Nazwa typu jest generowana przez kompilator i nie jest dostępna na poziomie kodu źródłowego. Typ każdej właściwości jest wnioskowany przez kompilator.

Typy anonimowe są tworzone przy użyciu new operatora razem z inicjatorem obiektów. Aby uzyskać więcej informacji na temat inicjatorów obiektów, zobacz Inicjatory obiektów i kolekcji.

W poniższym przykładzie pokazano typ anonimowy zainicjowany z dwiema właściwościami o nazwie Amount i 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);

Typy anonimowe są zwykle używane w select klauzuli wyrażenia zapytania w celu zwrócenia podzestawu właściwości z każdego obiektu w sekwencji źródłowej. Aby uzyskać więcej informacji na temat zapytań, zobacz LINQ w języku C#.

Typy anonimowe zawierają co najmniej jedną publiczną właściwość tylko do odczytu. Żadne inne rodzaje składowych klas, takich jak metody lub zdarzenia, są prawidłowe. Wyrażenie używane do inicjowania właściwości nie może być nullfunkcją anonimową lub typem wskaźnika.

Najczęstszym scenariuszem jest zainicjowanie typu anonimowego z właściwościami z innego typu. W poniższym przykładzie przyjęto założenie, że istnieje klasa o nazwie Product. Klasa Product zawiera Color właściwości i Price wraz z innymi właściwościami, których nie interesujesz. Zmienna products jest kolekcją Product obiektów. Deklaracja typu anonimowego rozpoczyna się od słowa kluczowego new . Deklaracja inicjuje nowy typ, który używa tylko dwóch właściwości z klasy Product. Użycie typów anonimowych powoduje zwrócenie mniejszej ilości danych w zapytaniu.

Jeśli nie określisz nazw składowych w typie anonimowym, kompilator nadaje anonimowym składowym typu taką samą nazwę jak właściwość używana do ich inicjowania. Należy podać nazwę właściwości, która jest inicjowana za pomocą wyrażenia, jak pokazano w poprzednim przykładzie. W poniższym przykładzie nazwy właściwości typu anonimowego to Color i Price.

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);
}

Napiwek

Możesz użyć reguły stylu platformy .NET IDE0037, aby wymusić, czy wywnioskowane lub jawne nazwy elementów członkowskich są preferowane.

Istnieje również możliwość zdefiniowania pola według obiektu innego typu: klasy, struktury lub nawet innego typu anonimowego. Odbywa się to przy użyciu zmiennej zawierającej ten obiekt tak samo jak w poniższym przykładzie, w którym tworzone są dwa typy anonimowe przy użyciu już utworzonych typów zdefiniowanych przez użytkownika. W obu przypadkach product pole typu anonimowego shipment będzie shipmentWithBonusProduct zawierać wartości domyślne każdego pola. bonus Pole będzie typu anonimowego utworzonego przez kompilator.

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 };

Zazwyczaj w przypadku użycia typu anonimowego do zainicjowania zmiennej należy zadeklarować zmienną jako niejawnie typizowanej zmiennej lokalnej przy użyciu zmiennej var. Nie można określić nazwy typu w deklaracji zmiennej, ponieważ tylko kompilator ma dostęp do bazowej nazwy typu anonimowego. Aby uzyskać więcej informacji na temat varprogramu , zobacz Niejawnie typizowane zmienne lokalne.

Można utworzyć tablicę anonimowo wpisanych elementów, łącząc niejawnie typizowanej zmiennej lokalnej i niejawnie typizowanej tablicy, jak pokazano w poniższym przykładzie.

var anonArray = new[] { new { name = "apple", diam = 4 }, new { name = "grape", diam = 1 }};

Typy anonimowe to class typy, które pochodzą bezpośrednio z objectklasy , i które nie mogą być rzutowane do dowolnego typu, z wyjątkiem object. Kompilator udostępnia nazwę dla każdego typu anonimowego, chociaż aplikacja nie może uzyskać do niej dostępu. Z perspektywy środowiska uruchomieniowego języka wspólnego typ anonimowy nie różni się od innego typu odwołania.

Jeśli co najmniej dwa anonimowe inicjatory obiektów w zestawie określ sekwencję właściwości, które znajdują się w tej samej kolejności i które mają takie same nazwy i typy, kompilator traktuje obiekty jako wystąpienia tego samego typu. Współużytkują te same informacje o typie generowanym przez kompilator.

Typy anonimowe obsługują mutację niedestrukcyjną w postaci wyrażeń. Dzięki temu można utworzyć nowe wystąpienie typu anonimowego, w którym co najmniej jedna właściwości ma nowe wartości:

var apple = new { Item = "apples", Price = 1.35 };
var onSale = apple with { Price = 0.79 };
Console.WriteLine(apple);
Console.WriteLine(onSale);

Nie można zadeklarować pola, właściwości, zdarzenia lub zwracanego typu metody jako typu anonimowego. Podobnie nie można zadeklarować parametru formalnego metody, właściwości, konstruktora lub indeksatora jako typu anonimowego. Aby przekazać typ anonimowy lub kolekcję zawierającą typy anonimowe, jako argument metody, można zadeklarować parametr jako typ object. Jednak użycie object w przypadku typów anonimowych pokonuje cel silnego pisania. Jeśli musisz przechowywać wyniki zapytania lub przekazywać je poza granicę metody, rozważ użycie zwykłej, nazwanej struktury lub klasy zamiast typu anonimowego.

Equals Ponieważ metody i GetHashCode dla typów anonimowych są zdefiniowane pod względem Equals właściwości iGetHashCode, dwa wystąpienia tego samego typu anonimowego są równe tylko wtedy, gdy wszystkie ich właściwości są równe.

Uwaga

Poziom ułatwień dostępu typu anonimowego to internal, dlatego dwa typy anonimowe zdefiniowane w różnych zestawach nie są tego samego typu. W związku z tym wystąpienia typów anonimowych nie mogą być równe sobie podczas definiowania w różnych zestawach, nawet jeśli wszystkie ich właściwości są równe.

Typy anonimowe zastępują metodę ToString , łącząc nazwę i ToString dane wyjściowe każdej właściwości otoczonej nawiasami klamrowymi.

var v = new { Title = "Hello", Age = 24 };

Console.WriteLine(v.ToString()); // "{ Title = Hello, Age = 24 }"