Megosztás a következőn keresztül:


Tuples és névtelen típusok

A Tuples egy egyszerű adatstruktúrát biztosít több tag számára egyetlen struktúrában. Ezek az előnyben részesített választás a névtelen típusokkal szemben. A tuple-ök jobb teljesítményt biztosítanak, támogatják a bontást, és rugalmasabb szintaxissal rendelkeznek.

A névtelen típusokkal kényelmesen ágyazhat be írásvédett tulajdonságokat egyetlen objektumba anélkül, hogy először explicit módon kellene definiálnia egy típust. A fordító létrehozza a típusnevet, és nem érhető el a forráskód szintjén. A fordító következtet a tulajdonságok típusára. A névtelen típusokat elsősorban akkor használja, ha kifejezésfa-támogatásra van szüksége, vagy ha referenciatípusokat igénylő kóddal dolgozik.

Tuples és névtelen típusok

A tuples és a névtelen típus egyaránt lehetővé teszi több érték csoportosítását nevesített típus definiálása nélkül. A tuple-k azonban jobb nyelvi támogatással rendelkeznek, és hatékonyabb adatstruktúrára kompilálódnak. Az alábbi táblázat összefoglalja a főbb különbségeket:

Tulajdonság Névtelen típusok Tupolok
Típus Hivatkozás típusa (class) Érték típusa (struct)
Performance Halom lefoglalása Veremfoglalás (jobb teljesítmény)
Mutability Írásvédett tulajdonságok Megváltoztatható mezők
Dekonstruálás Nem támogatott Támogatott
Kifejezésfák Támogatott Nem támogatott
Hozzáférés-módosító internal public
Osztálytagnevek Kötelező vagy levezetett Nem kötelező (alapértelmezett névvel, például Item1: Item2)

Mikor érdemes használni a tuplet?

Használjon tömböt a következő esetekben:

  • Jobb teljesítményt érhet el, ha veremfoglalást használ.
  • Az értékeket külön változókra szeretné bontani.
  • Több értéket adsz vissza egy metódusból.
  • Nincs szükség kifejezésfa-támogatásra.

Az alábbi példa azt mutatja be, hogyan nyújtanak a tuples hasonló funkciókat a névtelen típusokhoz, tisztább szintaxissal:

// Tuple with named elements.
var tupleProduct = (Name: "Widget", Price: 19.99M);
Console.WriteLine($"Tuple: {tupleProduct.Name} costs ${tupleProduct.Price}");

// Equivalent example using anonymous types.
var anonymousProduct = new { Name = "Widget", Price = 19.99M };
Console.WriteLine($"Anonymous: {anonymousProduct.Name} costs ${anonymousProduct.Price}");

N-tuple szétbontás

A tupelt külön változókra bonthatja, így kényelmesen dolgozhat az egyes tupel elemeivel. A C# többféleképpen támogatja a tuple-ök lebontását.

static (string Name, int Age, string City) GetPersonInfo()
{
    return ("Alice", 30, "Seattle");
}
// Deconstruct using var for all variables
var (name, age, city) = GetPersonInfo();
Console.WriteLine($"{name} is {age} years old and lives in {city}");
// Output: Alice is 30 years old and lives in Seattle

// Deconstruct with explicit types
(string personName, int personAge, string personCity) = GetPersonInfo();
Console.WriteLine($"{personName}, {personAge}, {personCity}");

// Deconstruct into existing variables
string existingName;
int existingAge;
string existingCity;
(existingName, existingAge, existingCity) = GetPersonInfo();

// Deconstruct and discard unwanted values using the discard pattern (_)
var (name2, _, city2) = GetPersonInfo();
Console.WriteLine($"{name2} lives in {city2}");
// Output: Alice lives in Seattle

A dekonstruálás hurkokban és mintaegyeztetési forgatókönyvekben hasznos:

var people = new List<(string Name, int Age)>
{
    ("Bob", 25),
    ("Carol", 35),
    ("Dave", 40)
};

foreach (var (personName2, personAge2) in people)
{
    Console.WriteLine($"{personName2} is {personAge2} years old");
}

Tuples mint metódus visszatérési típusa

A tuple-k gyakori használati esete a metódus visszatérési típusaként való alkalmazás. out paraméterek definiálása helyett csoportosíthatja a metódusok eredményeit egy tupelben. Nem adhat vissza névtelen típust egy metódusból, mert nincs neve, és a visszatérési típus nem deklarálható.

Az alábbi példa bemutatja, hogy a konfigurációs tartományok visszaadásához tupleseket használ szótárkeresésekkel.

var configLookup = new Dictionary<int, (int Min, int Max)>()
{
    [2] = (4, 10),
    [4] = (10, 20),
    [6] = (0, 23)
};

if (configLookup.TryGetValue(4, out (int Min, int Max) range))
{
    Console.WriteLine($"Found range: min is {range.Min}, max is {range.Max}");
}
// Output: Found range: min is 10, max is 20

Ez a minta akkor hasznos, ha olyan metódusokkal dolgozik, amelyeknek sikermutatót és több eredményértéket is vissza kell adniuk. A tuple lehetővé teszi, hogy nevesített mezőket (Min és Max) használjon az általános nevek helyett, például Item1 és Item2, így a kód olvashatóbb és önaláírásosabbá válik.

Mikor érdemes névtelen típusokat használni?

Névtelen típusokat akkor használjon, ha:

  • Ön kifejezésfákkal dolgozik (például néhány Microsoft Language-Integrated Query (LINQ) szolgáltatónál).
  • Az objektumnak referenciatípusnak kell lennie.

A leggyakoribb forgatókönyv egy névtelen típus inicializálása egy másik típus tulajdonságaival. Az alábbi példában tegyük fel, hogy létezik egy osztály, amely neve Product. Az osztály Product tartalmazza a Color és Price tulajdonságokat, valamint más olyan tulajdonságokat, amelyek nem érdekelnek.

class Product
{
    public string? Color { get; init; }
    public decimal Price { get; init; }
    public string? Name { get; init; }
    public string? Category { get; init; }
    public string? Size { get; init; }
}

A névtelen típusdeklaráció az new operátorral és egy objektum inicializálójával kezdődik. A deklaráció inicializál egy új típust, amely csak két tulajdonságot használ.Product A névtelen típusokat általában a select lekérdezési kifejezés záradékában használják kisebb mennyiségű adat visszaadására. További információ a lekérdezésekről: LINQ in C#.

Ha nem ad meg tagneveket névtelen típusban, a fordító ugyanazt a nevet adja a névtelen típustagoknak, mint az inicializálásukhoz használt tulajdonság. Egy kifejezéssel inicializálandó tulajdonság nevét adja meg, ahogy az előző példában is látható.

Az alábbi példában a névtelen típus tulajdonságainak nevei a következők Color : és Price. A példányok a products gyűjtemény Product típusú elemei:

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

Névtelen típusok előrejelzési inicializálói

A névtelen típusok támogatják a kivetítési inicializálókat, amelyek lehetővé teszik helyi változók vagy paraméterek közvetlen használatát a tagnév explicit megadása nélkül. A fordító a változónevekből következtet a tagnevekre. Az alábbi példa ezt az egyszerűsített szintaxist mutatja be:

// Explicit member names.
var personExplicit = new { FirstName = "Kyle", LastName = "Mit" };

// Projection initializers (inferred member names).
var firstName = "Kyle";
var lastName = "Mit";
var personInferred = new { firstName, lastName };

// Both create equivalent anonymous types with the same property names.
Console.WriteLine($"Explicit: {personExplicit.FirstName} {personExplicit.LastName}");
Console.WriteLine($"Inferred: {personInferred.firstName} {personInferred.lastName}");

Ez az egyszerűsített szintaxis akkor hasznos, ha sok tulajdonsággal rendelkező névtelen típusokat hoz létre:

var title = "Software Engineer";
var department = "Engineering";
var salary = 75000;

// Using projection initializers.
var employee = new { title, department, salary };

// Equivalent to explicit syntax:
// var employee = new { title = title, department = department, salary = salary };

Console.WriteLine($"Title: {employee.title}, Department: {employee.department}, Salary: {employee.salary}");

A tag neve nem származtatható a következő esetekben:

  • A jelölt neve azonos névtelen típusban duplikál egy másik tulajdonságtagot, explicit vagy implicit módon.
  • A jelölt neve nem érvényes azonosító (például szóközöket vagy speciális karaktereket tartalmaz).

Ezekben az esetekben explicit módon meg kell adnia a tag nevét.

Tipp.

A .NET stílusszabály IDE0037 használatával kikényszerítheti, hogy a kikövetkesített vagy explicit tagnevek legyenek-e előnyben részesítve.

A mezőket egy másik típusú objektummal is definiálhatja: osztály, struktúra vagy akár egy másik névtelen típus. Ehhez használja az objektumot tartalmazó változót. Az alábbi példa két névtelen típust mutat be, amelyek már példányosított, felhasználó által definiált típusokat használnak. Mindkét esetben a product névtelen típusú shipment és shipmentWithBonus típusú Product mező tartalmazza az egyes mezők alapértelmezett értékeit. A bonus mező a fordító által létrehozott névtelen típusú.

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

Ha egy változó inicializálásához névtelen típust használ, a változót implicit módon beírt helyi változóként deklarálja var használatával. A változó deklarációjában nem adhatja meg a típusnevet, mert csak a fordító rendelkezik hozzáféréssel a névtelen típus alapjául szolgáló névhez. További információ: varImplicit módon beírt helyi változók.

Névtelenül beírt elemekből álló tömböt úgy hozhat létre, hogy egy implicit módon beírt helyi változót és egy implicit módon beírt tömböt kombinál az alábbi példában látható módon.

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

A névtelen típusok class olyan típusok, amelyek közvetlenül a object-ből származnak, és nem lehet őket átkonvertálni semmilyen típusra, kivéve object. A fordító minden névtelen típushoz megad egy nevet, bár az alkalmazás nem fér hozzá. A közös nyelvi futtatókörnyezet szempontjából a névtelen típus nem különbözik a többi referenciatípustól.

Ha egy szerelvény két vagy több névtelen objektum-inicializálója azonos sorrendben, azonos nevű és típusú tulajdonságok sorozatát adja meg, a fordító az objektumokat azonos típusú példányokként kezeli. Ugyanazokkal a fordító által generált típusinformációkat osztják meg.

A névtelen típusok kifejezésekkel támogatják a roncsolásmentes mutációt. Ez a funkció lehetővé teszi egy névtelen típusú új példány létrehozását, amelyben egy vagy több tulajdonság új értékekkel rendelkezik:

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

Nem deklarálhat egy mezőt, tulajdonságot, eseményt vagy metódus visszatérési típusát névtelen típusként. Hasonlóképpen nem deklarálhatja egy metódus, tulajdonság, konstruktor vagy indexelő formális paraméterét névtelen típusként. Ha névtelen típust vagy névtelen típusokat tartalmazó gyűjteményt szeretne átadni egy metódus argumentumaként, a paramétert típusként objectdeklarálhatja. A névtelen típusok használata object azonban nem célja az erős gépelésnek. Ha a lekérdezési eredményeket el kell tárolnia, vagy át kell adnia őket a metódushatáron kívül, fontolja meg egy névvel ellátott struktúra vagy osztály használatát névtelen típus helyett.

Mivel a Equals névtelen típusok és GetHashCode metódusok a tulajdonságok és Equals metódusok szempontjából vannak definiálvaGetHashCode, két azonos névtelen típusú példány csak akkor egyenlő, ha az összes tulajdonságuk egyenlő.

Feljegyzés

A névtelen típus akadálymentességi szintje a következő internal: . Ezért a különböző szerelvényekben definiált két névtelen típus nem ugyanazon típusú. Ezért a névtelen típusok példányai nem lehetnek egyenlők egymással, ha különböző szerelvényekben vannak definiálva, még akkor sem, ha minden tulajdonságuk egyenlő.

A névtelen típusok felülírják a ToString metódust, összefűzve a kapcsos zárójelekkel körülvett összes tulajdonság nevét és ToString kimenetét.

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

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

Lásd még