Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Typ sjednocení představuje hodnotu, která může být jedním z několika typů případů. Sjednocení poskytují implicitní převody z každého typu případu, vyčerpávající porovnávání vzorů a sledování rozšířené hodnoty nullability. Pomocí klíčového union slova deklarujte typ sjednocení:
public union Pet(Cat, Dog, Bird);
Tato deklarace vytvoří sjednocení se třemi Pet typy případů: Cat, Doga Bird. Proměnné můžete přiřadit libovolnou Pet hodnotu typu případu. Kompilátor zajišťuje, že switch výrazy pokrývají všechny typy případů.
Referenční dokumentace jazyka C# dokumentuje naposledy vydané verze jazyka C#. Obsahuje také počáteční dokumentaci k funkcím ve verzi Public Preview pro nadcházející jazykovou verzi.
Dokumentace identifikuje všechny funkce, které byly poprvé představeny v posledních třech verzích jazyka nebo v aktuálních verzích Public Preview.
Návod
Informace o tom, kdy byla funkce poprvé představena v jazyce C#, najdete v článku o historii verzí jazyka C#.
Deklarujte sjednocení, pokud hodnota musí být přesně jednou z pevných množiny typů a chcete, aby kompilátor vynucoval, aby se každá možnost zpracovala. Mezi běžné scénáře patří:
-
Vrátí výsledek nebo chybu: Metoda vrátí hodnotu úspěchu nebo chybovou hodnotu a volající musí zpracovat obojí. Sjednocením je
union Result(Success, Error)sada výsledků explicitní. -
Odesílání zpráv nebo příkazů: Systém zpracovává uzavřenou sadu typů zpráv. Sjednocení zajišťuje, že nové typy zpráv vytvářejí upozornění v době kompilace v každém
switch, který je ještě nezpracuje. - Nahrazení rozhraní značek nebo abstraktních základních tříd: Pokud používáte rozhraní nebo abstraktní třídu výhradně k seskupení typů pro porovnávání vzorů, sjednocení poskytuje kontrolu úplnosti bez nutnosti dědičnosti nebo sdílených členů.
Sjednocení se liší od jiných deklarací typů důležitými způsoby:
-
classNa rozdíl od nebostructnedefinuje sjednocení nové datové členy. Místo toho vytvoří existující typy do uzavřené sady alternativ. -
interfaceNa rozdíl od sjednocování je uzavřeno – definujete úplný seznam typů případů v deklaraci a kompilátor použije tento seznam k kontrolám úplnosti. -
recordNa rozdíl od sjednocení nepřidává chování rovnosti, klonování ani dekonstrukce. Sjednocení se zaměřuje na "jaký případ je?" a ne na to, jaká pole mají?
Důležité
V .NET 11 Preview 2 modul runtime neobsahuje rozhraní UnionAttribute a IUnion rozhraní. Pokud chcete použít typy sjednocení, musíte je deklarovat sami. Pokud chcete zobrazit požadované deklarace, přečtěte si téma Implementace Unie.
Deklarace sjednocení
Deklarace sjednocení určuje název a seznam typů případů:
public union Pet(Cat, Dog, Bird);
Typy případů mohou být libovolný typ, který se převede na objecttřídy, struktury, rozhraní, parametry typu, typy s možnou hodnotou null a další sjednocení. Následující příklady ukazují různé možnosti typů případů:
public record class Cat(string Name);
public record class Dog(string Name);
public record class Bird(string Name);
public record class None;
public record class Some<T>(T Value);
public union Option<T>(None, Some<T>);
public union IntOrString(int, string);
Pokud je typem případu typ hodnoty (například int), hodnota se zadává do pole, když je uložena Value ve vlastnosti sjednocení. Sjednocení ukládají jejich obsah jako jediný object? odkaz.
Deklarace sjednocení může obsahovat tělo s dalšími členy, stejně jako struktura, s výhradou některých omezení. Deklarace sjednocení nemůžou obsahovat pole instancí, automatické vlastnosti ani události podobné polím. Nemůžete také deklarovat veřejné konstruktory s jedním parametrem, protože kompilátor generuje tyto konstruktory jako členy vytváření sjednocení:
public union OneOrMore<T>(T, IEnumerable<T>)
{
public IEnumerable<T> AsEnumerable() => Value switch
{
T single => [single],
IEnumerable<T> multiple => multiple,
_ => []
};
}
Sjednocení převodů
Implicitní sjednocovacího převodu existuje z každého typu případu na typ sjednocení. Konstruktor nemusíte volat explicitně:
static void BasicConversion()
{
Pet pet = new Dog("Rex");
Console.WriteLine(pet.Value); // output: Dog { Name = Rex }
Pet pet2 = new Cat("Whiskers");
Console.WriteLine(pet2.Value); // output: Cat { Name = Whiskers }
}
Sjednocovací převody fungují voláním odpovídajícího generovaného konstruktoru. Pokud existuje operátor implicitního převodu definovaný uživatelem pro stejný typ, má operátor definovaný uživatelem přednost před sjednocovacího převodu. Podrobnosti o prioritě převodu najdete ve specifikaci jazyka.
Převod sjednocení na strukturu sjednocení s možnou hodnotou null (T?) funguje také v případech, kdy T je sjednocovací typ:
static void NullableUnionExample()
{
Pet? maybePet = new Dog("Buddy");
Pet? noPet = null;
Console.WriteLine(Describe(maybePet)); // output: Dog: Buddy
Console.WriteLine(Describe(noPet)); // output: no pet
static string Describe(Pet? pet) => pet switch
{
Dog d => d.Name,
Cat c => c.Name,
Bird b => b.Name,
null => "no pet",
};
}
Sjednocování
Pokud porovnáváte vzory u sjednocovacího typu, vzory se vztahují na vlastnost sjednocení Value , nikoli na samotnou sjednocovatelskou hodnotu. Toto chování při rozbalování znamená, že sjednocení je transparentní pro porovnávání vzorů:
static void PatternMatching()
{
Pet pet = new Dog("Rex");
var name = pet switch
{
Dog d => d.Name,
Cat c => c.Name,
Bird b => b.Name,
};
Console.WriteLine(name); // output: Rex
}
Dva vzory jsou výjimky tohoto pravidla: var vzor a zahodit vzor platí pro samotnou sjednocovat _ hodnotu, nikoli její Value vlastnost. Slouží var k zachycení sjednocovacího hodnoty při GetPet() vrácení hodnoty Pet? (Nullable<Pet>):
if (GetPet() is var pet) { /* pet is the Pet? value returned from GetPet */ }
V logických vzorech se každá větev řídí pravidlem rozbalování jednotlivě. Následující vzor testuje, že Pet? není null a jeho Value hodnota není null:
GetPet() switch
{
var pet and not null => ..., // 'var pet' captures the Pet?; 'not null' checks Value
}
Poznámka:
Vzhledem k tomu, že vzory platí pro Value, vzor jako pet is Pet obvykle neodpovídá, protože Pet se testuje s obsahem sjednocení, nikoli samotné sjednocení.
Porovnávání s hodnotou Null
U sjednocení struktur vzor kontroluje, null jestli Value má hodnotu null:
static void NullHandling()
{
Pet pet = default;
Console.WriteLine(pet.Value is null); // output: True
var description = pet switch
{
Dog d => d.Name,
Cat c => c.Name,
Bird b => b.Name,
null => "no pet",
};
Console.WriteLine(description); // output: no pet
}
U sjednocení založených na třídách je úspěšné, null pokud je odkaz na sjednocení samotný null nebo jeho Value vlastnost má hodnotu null:
Result<string>? result = null;
if (result is null) { /* true — the reference is null */ }
Result<string> empty = new Result<string>((string?)null);
if (empty is null) { /* true — Value is null */ }
U typů struktury sjednocení s možnou hodnotou null (Pet?) proběhne úspěšně, null pokud obálka s možnou hodnotou null nemá žádnou hodnotu nebo pokud je podkladová sjednocení Value null.
Úplnost sjednocení
Výraz switch je vyčerpávající, když zpracovává všechny typy případů sjednocení. Kompilátor varuje pouze v případě, že typ případu není zpracován. Nemusíte zadávat vzor zahození (_) ani var vzor, aby odpovídal jakémukoli typu:
static void PatternMatching()
{
Pet pet = new Dog("Rex");
var name = pet switch
{
Dog d => d.Name,
Cat c => c.Name,
Bird b => b.Name,
};
Console.WriteLine(name); // output: Rex
}
Pokud je stav null vlastnosti sjednocení Value "možná null", musíte také zpracovat null , aby se zabránilo upozornění:
static void NullHandling()
{
Pet pet = default;
Console.WriteLine(pet.Value is null); // output: True
var description = pet switch
{
Dog d => d.Name,
Cat c => c.Name,
Bird b => b.Name,
null => "no pet",
};
Console.WriteLine(description); // output: no pet
}
Nullovatelnost
Kompilátor sleduje stav null vlastnosti sjednocení Value pomocí následujících pravidel:
- Když vytvoříte sjednocovací hodnotu z typu případu (prostřednictvím konstruktoru nebo sjednocovacího převodu),
Valuezíská stav null příchozí hodnoty. - Při dotazování obsahu sjednocovacího modelu
HasValueneboTryGetValue(...)členů modelu přístupu se stavValuenull ve větvi změní natruehodnotu "not null".
Vlastní typy sjednocení
Kompilátor převede union deklaraci na struct deklaraci. Struktura je označena atributem [System.Runtime.CompilerServices.Union] , implementuje IUnion rozhraní. Zahrnuje veřejný konstruktor a implicitní převod pro každý typ případu spolu s Value vlastností. Tento vygenerovaný formulář je názorný. Vždy se jedná o strukturu, vždy pole hodnotových případů a vždy ukládá obsah jako object?.
Pokud potřebujete jiné chování , například sjednocení založené na třídě, vlastní strategii úložiště, podporu vzájemné spolupráce nebo pokud chcete přizpůsobit existující typ, můžete typ sjednocení vytvořit ručně.
Jakákoli třída nebo struktura s atributem [Union] je typ sjednocení , pokud se řídí základním vzorem sjednocení. Základní sjednocovacího vzoru vyžaduje:
- Atribut
[Union]typu. - Jeden nebo více veřejných konstruktorů, z nichž každý má jednu hodnotu nebo
inparametr. Typ parametru každého konstruktoru definuje typ případu. - Veřejná
Valuevlastnost typuobject?(neboobject) s příslušenstvímget.
Všichni členové odborů musí být veřejná. Kompilátor tyto členy používá k implementaci sjednocovacího převodu, porovnávání vzorů a kontrol úplnosti. Můžete také implementovat vzor přístupu bez rámečku nebo vytvořit typ sjednocení založené na třídách.
Kompilátor předpokládá, že vlastní typy sjednocení vyhovují těmto pravidlům chování:
-
Zvuk:
Valuevždy vrátínullhodnotu nebo hodnotu jednoho z typů případů – nikdy hodnotu jiného typu. Pro sjednocení strukturdefaultvytvoří zValuenull. -
Stabilita: Pokud vytvoříte sjednocovat hodnotu z typu případu,
Valueodpovídá tomuto typu případu (nebo je-linullvstupnull). - Ekvivalence vytvoření: Pokud je hodnota implicitně konvertibilní na dva různé typy případů, oba členy vytváření vytvářejí stejné pozorovatelné chování.
-
Konzistence vzorů přístupu: Členové
HasValueaTryGetValuečlenové se chovají stejně jako při kontroleValuepřímo.
Následující příklad ukazuje vlastní typ sjednocení:
[System.Runtime.CompilerServices.Union]
public struct Shape : System.Runtime.CompilerServices.IUnion
{
private readonly object? _value;
public Shape(Circle value) { _value = value; }
public Shape(Rectangle value) { _value = value; }
public object? Value => _value;
}
public record class Circle(double Radius);
public record class Rectangle(double Width, double Height);
static void ManualUnionExample()
{
Shape shape = new Shape(new Circle(5.0));
var area = shape switch
{
Circle c => Math.PI * c.Radius * c.Radius,
Rectangle r => r.Width * r.Height,
};
Console.WriteLine($"{area:F2}"); // output: 78.54
}
Vzor přístupu bez boxování
Vlastní sjednocovací typ může volitelně implementovat vzor přístupu bez boxingu , který umožňuje přístup silného typu k případům typu hodnota bez boxování během porovnávání vzorů. Tento model vyžaduje:
- Vlastnost
HasValuetypubool, která vracítrue, kdyžValuenenínull. - Metoda
TryGetValuepro každý typ případu, který vrátíboola doručí hodnotu prostřednictvím parametruout.
[System.Runtime.CompilerServices.Union]
public struct IntOrBool : System.Runtime.CompilerServices.IUnion
{
private readonly int _intValue;
private readonly bool _boolValue;
private readonly byte _tag; // 0 = none, 1 = int, 2 = bool
public IntOrBool(int? value)
{
if (value.HasValue)
{
_intValue = value.Value;
_tag = 1;
}
}
public IntOrBool(bool? value)
{
if (value.HasValue)
{
_boolValue = value.Value;
_tag = 2;
}
}
public object? Value => _tag switch
{
1 => _intValue,
2 => _boolValue,
_ => null
};
public bool HasValue => _tag != 0;
public bool TryGetValue(out int value)
{
value = _intValue;
return _tag == 1;
}
public bool TryGetValue(out bool value)
{
value = _boolValue;
return _tag == 2;
}
}
static void NonBoxingExample()
{
IntOrBool val = new IntOrBool((int?)42);
var description = val switch
{
int i => $"int: {i}",
bool b => $"bool: {b}",
};
Console.WriteLine(description); // output: int: 42
}
Kompilátor dává přednost TryGetValue před Value vlastností při implementaci porovnávání vzorů, což zabraňuje krabicové typy hodnot.
Typy sjednocení založené na třídách
Třída může být také sjednocovacího typu. Tento typ sjednocení je užitečný v případě, že potřebujete referenční sémantiku nebo dědičnost:
[System.Runtime.CompilerServices.Union]
public class Result<T> : System.Runtime.CompilerServices.IUnion
{
private readonly object? _value;
public Result(T? value) { _value = value; }
public Result(Exception? value) { _value = value; }
public object? Value => _value;
}
static void ClassUnionExample()
{
Result<string> ok = new Result<string>("success");
Result<string> err = new Result<string>(new InvalidOperationException("failed"));
Console.WriteLine(Describe(ok)); // output: OK: success
Console.WriteLine(Describe(err)); // output: Error: failed
static string Describe(Result<string> result) => result switch
{
string s => $"OK: {s}",
Exception e => $"Error: {e.Message}",
null => "null",
};
}
U sjednocení založených na třídách null vzor odpovídá odkazu null i hodnotě null Value.
Implementace Unie
Následující atribut a rozhraní podporují typy sjednocení v době kompilace a za běhu:
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false)]
public sealed class UnionAttribute : Attribute;
public interface IUnion
{
object? Value { get; }
}
}
Deklarace Sjednocení generované kompilátorem implementují IUnion. Libovolnou hodnotu sjednocení můžete zkontrolovat za běhu pomocí IUnion:
if (value is IUnion { Value: null }) { /* the union's value is null */ }
Když deklarujete union typ, kompilátor vygeneruje strukturu, která implementuje IUnion. Deklarace (public union Pet(Cat, Dog, Bird);) se například Pet stane ekvivalentem:
[Union] public struct Pet : IUnion
{
public Pet(Cat value) => Value = value;
public Pet(Dog value) => Value = value;
public Pet(Bird value) => Value = value;
public object? Value { get; }
}
Důležité
V .NET 11 Preview 2 nejsou tyto typy zahrnuty do modulu runtime. Chcete-li použít typy sjednocení, musíte je deklarovat v projektu. Budou zahrnuté v budoucí verzi .NET Preview.
specifikace jazyka C#
Další informace najdete ve specifikaci funkcí Sjednocení .
Viz také
- Systém typů jazyka C#
- Porovnávání vzorů
- Výraz Switch
- typy hodnot
- Záznamy