Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Een samenvoegtype vertegenwoordigt een waarde die een van de verschillende casetypen kan zijn. Samenvoegingen bieden impliciete conversies van elk casetype, volledige patroonkoppeling en verbeterde tracering van null-waarden. Gebruik het union trefwoord om een samenvoegtype te declareren:
public union Pet(Cat, Dog, Bird);
Met deze declaratie wordt een Pet samenvoeging gemaakt met drie casetypen: Cat, Dogen Bird. U kunt elke waarde van het casetype toewijzen aan een Pet variabele. De compiler zorgt ervoor dat switch expressies alle casetypen behandelen.
De C#-taalreferentiedocumenten beschrijven de meest recent uitgebrachte versie van de C#-taal. Het bevat ook de eerste documentatie voor functies in openbare previews voor de aanstaande taalrelease.
De documentatie identificeert alle functies die voor het eerst zijn geïntroduceerd in de laatste drie versies van de taal of in de huidige openbare previews.
Aanbeveling
Raadpleeg het artikel over de versiegeschiedenis van de C#-taal om te achterhalen wanneer een functie voor het eerst is geïntroduceerd in C#.
Declareer een samenvoeging wanneer een waarde precies een van een vaste set typen moet zijn en u wilt dat de compiler afdwingt dat elke mogelijkheid wordt afgehandeld. Veelvoorkomende scenario's zijn onder andere:
-
Resultaat-of-fout retourneert: Een methode retourneert een succeswaarde of een foutwaarde en de aanroeper moet beide afhandelen. Een samenvoeging zoals
union Result(Success, Error)maakt de set resultaten expliciet. -
Bericht- of opdrachtverzending: een systeem verwerkt een gesloten set berichttypen. Een samenvoeging zorgt ervoor dat nieuwe berichttypen compilatietijdwaarschuwingen produceren voor elk
switchbericht dat deze nog niet verwerkt. - Markeringsinterfaces of abstracte basisklassen vervangen: Als u een interface of abstracte klasse alleen gebruikt om typen te groeperen voor patroonkoppeling, biedt een samenvoeging u volledigheidscontrole zonder overname of gedeelde leden te vereisen.
Een samenvoeging verschilt van andere typedeclaraties op belangrijke manieren:
- In tegenstelling tot een
classofstructdefinieert een samenvoeging geen nieuwe gegevensleden. In plaats daarvan bestaat het uit bestaande typen in een gesloten set alternatieven. - In tegenstelling tot een
interface, wordt een samenvoeging gesloten: u definieert de volledige lijst met casetypen in de declaratie en de compiler gebruikt die lijst voor volledigheidscontroles. - In tegenstelling tot een
record, voegt een samenvoeging geen gelijkheids-, kloon- of destructiegedrag toe. Een samenvoeging richt zich op 'welk geval is het?' in plaats van 'welke velden heeft het?'
Samenvoegtypen zijn afhankelijk van de UnionAttribute en IUnion typen in de System.Runtime.CompilerServices naamruimte. De .NET 11 runtime bevat deze typen.
Verklaringen van de Unie
Een samenvoegdeclaratie geeft een naam en een lijst met casetypen op:
public union Pet(Cat, Dog, Bird);
Casetypen kunnen elk type zijn dat wordt geconverteerd naar object, inclusief klassen, structs, interfaces, typeparameters, null-typen en andere samenvoegingen. In de volgende voorbeelden ziet u verschillende mogelijkheden voor casetypen:
public record class Cat(string Name);
public record class Dog(string Name, string Breed);
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);
Wanneer een casetype een waardetype is (zoals int), wordt de waarde door een samenvoegingsdeclaratie in de vakken opgeslagen als één object? verwijzing.
Aangepaste samenvoegtypen kunnen een andere opslagstrategie gebruiken.
Een samenvoegingsdeclaratie kan een orgaan met extra leden bevatten, net als een struct, onder bepaalde beperkingen. Samenvoegdeclaraties kunnen geen exemplaarvelden, auto-eigenschappen of veldachtige gebeurtenissen bevatten. U kunt ook geen openbare constructors met één parameter declareren, omdat de compiler deze constructors genereert als leden van het maken van een samenvoeging. Elke constructor die u declareert, moet een this(...) initialisatiefunctie gebruiken om rechtstreeks of indirect te delegeren aan een gegenereerde constructor. Met de volgende Length samenvoeging wordt een TotalMeters eigenschap toegevoegd die gebruikmaakt van patroonkoppeling om elk casetype te verwerken, samen met een Add methode die twee lengten combineert:
public record class Meters(double Value);
public record class Feet(double Value);
public union Length(Meters, Feet)
{
public double TotalMeters => this switch
{
Meters m => m.Value,
Feet f => f.Value * 0.3048,
_ => throw new InvalidOperationException("The Length has no value."),
};
public Length Add(Length other) => new Meters(TotalMeters + other.TotalMeters);
}
Samenvoegconversies
Er bestaat een impliciete samenvoegingsconversie van elk casetype naar het samenvoegtype:
static void BasicConversion()
{
Pet pet = new Dog("Rex", "Labrador");
Console.WriteLine(pet.Value); // output: Dog { Name = Rex, Breed = Labrador }
Pet pet2 = new Cat("Whiskers");
Console.WriteLine(pet2.Value); // output: Cat { Name = Whiskers }
}
Samenvoegconversies werken door de bijbehorende gegenereerde constructor aan te roepen. Als er een door de gebruiker gedefinieerde impliciete conversieoperator bestaat voor hetzelfde type, heeft de door de gebruiker gedefinieerde operator voorrang op de samenvoegconversie. Als meer dan één casetype even van toepassing is op de bronwaarde, is de samenvoegingsconversie dubbelzinnig en rapporteert de compiler een fout. Zie de functiespecificatie voor meer informatie over conversieprioriteit.
Een samenvoegingsconversie naar een struct (T?) werkt ook wanneer T een samenvoegingstype is:
static void NullableUnionExample()
{
Pet? maybePet = new Dog("Buddy", "Beagle");
Pet? noPet = null;
Console.WriteLine(Describe(maybePet)); // output: 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",
};
}
Union pattern matching
Wanneer u een type- of declaratiepatroon voor een samenvoegingsexpressie gebruikt, wordt de inhoud van de samenvoeging getest, niet het samenvoegexemplaren. Een patroon test bijvoorbeeld Dog of Value het een Dog:
static void PatternMatching()
{
Pet pet = new Dog("Rex", "Labrador");
var name = pet switch
{
Dog d => d.Name,
Cat c => c.Name,
Bird b => b.Name,
};
Console.WriteLine(name); // output: Rex
}
Het formulier van het patroon bepaalt welke waarde wordt getest:
| Pattern | Gedrag voor een samenvoegingsexpressie |
|---|---|
Type- of declaratiepatroon, zoals Dog of Dog dog |
Test de inhoud op basis van het opgegeven type. |
Eigenschap of positioneel patroon met een type, zoals Dog { Breed: "Labrador" } |
Test de inhoud op basis van het type en past vervolgens de geneste patronen toe op die casewaarde. |
Eigenschap of positioneel patroon zonder type, zoals { Name: "Rex" } |
Maakt gebruik van de eigenschappen of Deconstruct methode van het samenvoegexemplaren. |
| Lijstpatroon | Maakt gebruik van het aantal en de indexering van leden van het samenvoegexemplaren, niet die van de inhoud. |
varof patroon verwijderen _ |
Legt het binnenkomende samenvoegexemplaren vast of komt overeen zonder deze uit te pakken. |
| Constant of relationeel patroon | Test de inhoud. Het null patroon verwerkt ook een null-samenvoegingsreferentie of null-wrapper. |
Definieer bijvoorbeeld een Pet samenvoeging met een alleen-lezen Name eigenschap die delegert aan de ingesloten Cat eigenschap of Dog. Met de typepatronen in de expressie van switch de eigenschap wordt de inhoud getest:
public union Pet(Cat, Dog)
{
public string Name => this switch
{
Cat cat => cat.Name,
Dog dog => dog.Name,
null => "",
};
}
Het getypte patroon Dog { Breed: "Labrador" } test de inhoud en leest de eigenschap van Breedde hond, een eigenschap die de vereniging niet heeft. Het niet-getypte patroon { Name: "Rex" } leest in plaats daarvan de eigenschap van Name de vereniging, dus het komt ook overeen met een kat met de naam Rex:
Pet pet = new Dog("Rex", "Labrador");
Console.WriteLine(pet is Dog { Breed: "Labrador" }); // output: True
Console.WriteLine(pet is { Name: "Rex" }); // output: True
pet = new Cat("Rex");
Console.WriteLine(pet is Dog { Breed: "Labrador" }); // output: False
Console.WriteLine(pet is { Name: "Rex" }); // output: True
Het not patroon ontkent het geneste patroon. In pet is not null, het geneste null patroon controleert de inhoud, dus not null is een nuttige has-a-value test. Met een leeg niet-getypt eigenschapspatroon wordt { }daarentegen het samenvoegexemplaren gecontroleerd. Het komt altijd overeen met een niet-ullable struct-samenvoeging, zelfs wanneer Value null is:
Pet empty = default;
Console.WriteLine(empty is { }); // output: True
Console.WriteLine(empty is not null); // output: False
if (empty is var captured)
{
Console.WriteLine(captured.Value is null); // output: True
}
Logische patronen behouden deze verschillen.
var pet Legt var pet and not nullde binnenkomende samenvoeging vast en not null test of deze niet-null-inhoud bevat. In not null and var pethet var patroon wordt de binnenkomende samenvoeging nog steeds vastgelegd: not de waarde die wordt doorgegeven aan het rechterpatroon, wordt niet gewijzigd. Het typepatroon geeft daarentegen Dog and { Breed: "Labrador" }het overeenkomende Dog patroon door aan het eigenschapspatroon.
Opmerking
Een typepatroon moet compatibel zijn met ten minste één casetype. Voor de Pet declaraties in dit artikel pet is Pet produceert compilerfout CS8121: geen van hun casetypen kan overeenkomen Pet. Het is geen runtimetest van het samenvoegexemplaren. Als u wilt controleren op inhoud, gebruikt pet is not null of pet.Value is not null; om de samenvoeging zelf vast te leggen, gebruikt u een var patroon.
Kortom, type- en declaratiepatronen testen de inhoud. Recursieve patronen met een typetest de inhoud ook; recursieve patronen zonder type gebruiken de eigen leden van de unie. Deze regels zijn hetzelfde in een is expressie en een switch expressie.
Null-overeenkomende waarden
Voor struct-samenvoegingen controleert het null patroon of Value null is:
static void NullHandling()
{
Pet pet = default;
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
Console.WriteLine(pet.Value is null); // output: True
}
Voor op klassen gebaseerde samenvoegingen null slaagt wanneer de samenvoeging zelf null is of Value de eigenschap null is:
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 */ }
Voor structtypen voor null-waarden (Pet?), null slaagt het wanneer de waarde van de nullable wrapper geen waarde heeft of wanneer de onderliggende samenvoeging Value null is.
Uitputtendheid van de Unie
Een switch expressie is volledig ten opzichte van de casetypen van een samenvoeging wanneer elk casetype wordt verwerkt. Als een null-analyse ook rekening houdt met de inhoud die niet null is, hebt u geen verwijdering (_) of var arm nodig:
static void PatternMatching()
{
Pet pet = new Dog("Rex", "Labrador");
var name = pet switch
{
Dog d => d.Name,
Cat c => c.Name,
Bird b => b.Name,
};
Console.WriteLine(name); // output: Rex
}
Als u null-inhoud wilt verwerken, geeft u de voorkeur aan een null arm boven een var arm of verwijderen (_). Het null patroon geeft uw intentie aan en bewaart waarschuwingen wanneer u een nieuw casetype toevoegt zonder een overeenkomende arm. Een var of verwijderarm accepteert ook een nieuw geval, zodat de compiler u niet kan waarschuwen voor die ontbrekende zaak.
Wanneer de bijgehouden null-status Value 'misschien null' is, waarschuwt de compiler ook als u een null arm weglaat. Heeft bijvoorbeeld NullablePet een type null-case, zodat de inhoud van de parameter null kan zijn:
public union NullablePet(Cat?, Dog, Bird);
static string DescribeNullableCase(NullablePet pet) => pet switch
{
Cat cat => cat.Name,
Dog dog => dog.Name,
Bird bird => bird.Name,
null => "no pet",
};
Als u de null arm van deze schakelaar verwijdert, wordt de waarschuwing CS8655 gegenereerd.
Een null-analyse garandeert niet dat een gegenereerde samenvoeging tijdens runtime niet-null-inhoud heeft. Een standaard-samenvoeging bevat null, inclusief wanneer het een standaard-geïnitialiseerd veld of matrixelement is. Als alle casetypen niet kunnen worden uitgevoerd, is de standaard bijgehouden status Value echter 'niet null', dus de compiler waarschuwt niet noodzakelijkerwijs voor een weggelaten null arm. Greep null voor juistheid wanneer de standaardinhoud uw schakeloptie kan bereiken:
static void NullHandling()
{
Pet pet = default;
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
Console.WriteLine(pet.Value is null); // output: True
}
In dit Pet voorbeeld produceert het verwijderen van de null arm geen waarschuwing voor ontbrekende null-arm, tenzij eerdere code de bijgehouden null-status wijzigt, maar de schakeloptie genereert SwitchExpressionException wanneer deze de standaardwaarde ontvangt. Een eerdere is null test kan de bijgehouden status wijzigen en een waarschuwing veroorzaken. Dit gedrag staat los van de definitieve toewijzing: de compiler weigert een leesbewerking van een niet-toegewezen lokale variabele.
Nullbaarheid
De compiler houdt de null-status van de eigenschap van een samenvoeging Value bij via de volgende regels:
- De standaard null-status van de eigenschap van een samenvoeging
Valueis 'misschien null' als de standaard null-status van elk casetype 'misschien null' is. Anders is de standaard null-status 'not null'. - Wanneer u een samenvoegwaarde maakt op basis van een casetype (via een constructor of samenvoegconversie),
Valuewordt de null-status van de binnenkomende waarde opgehaald. - Wanneer de niet-boksende toegangspatronen
HasValueofTryGetValue(...)leden de inhoud vanValuede samenvoeging opvragen, wordt de null-status 'not null' op detruevertakking.
Aangepaste samenvoegtypen
De compiler converteert een union declaratie naar een struct declaratie. De struct is gemarkeerd met het [System.Runtime.CompilerServices.Union] kenmerk en implementeert de IUnion interface. Het bevat een openbare constructor voor elk casetype en een Value eigenschap. De taal biedt impliciete samenvoegingsconversies die deze constructors aanroepen. Dat gegenereerde formulier is geïmteerd. Het is altijd een struct, altijd vakken waarde-type cases en slaat altijd inhoud op als object?.
Mogelijk hebt u een ander gedrag nodig als u een bestaand type wilt aanpassen, een op klassen gebaseerde samenvoeging wilt maken of een aangepaste opslagstrategie wilt gebruiken, of als u ondersteuning voor samenwerking nodig hebt. U kunt handmatig een samenvoegtype maken.
Elke klasse of struct met een [Union] kenmerk is een samenvoegingstype als dit het basispatroon van de samenvoeging volgt. Voor het eenvoudige samenvoegpatroon is het volgende vereist:
- Een
[Union]kenmerk voor het type. - Een of meer openbare constructors, elk met één by-value of
inparameter. Het parametertype van elke constructor definieert een casetype. - Een openbare
Valueeigenschap van het typeobject?(ofobject) met eengettoegangsbeheerprogramma.
Alle voorgaande leden van de unie moeten openbaar zijn. De compiler gebruikt deze leden om samenvoegconversies, patroonkoppelingen en volledigheidscontroles te implementeren. U kunt ook het toegangspatroon voor niet-boksen implementeren of een op klassen gebaseerd samenvoegtype maken. Uw aangepaste samenvoegingstype kan meer leden toevoegen.
De compiler gaat ervan uit dat aangepaste samenvoegtypen voldoen aan deze gedragsregels:
-
Geluid:
Valueretourneertnullaltijd of een waarde van een van de casetypen, inclusief voor een standaardstructwaarde. Een aangepaste samenvoeging kan de standaardwaarde vertegenwoordigen als een niet-null-hoofdletter, in tegenstelling tot de null-inhoud van een standaard gegenereerde samenvoeging. -
Stabiliteit: Als u een samenvoegwaarde maakt op basis van een casetype,
Valuekomt dit overeen met dat casetype (ofnullals de invoer wasnull). - Gelijkwaardigheid creëren: als een waarde impliciet wordt omgezet in twee verschillende casetypen, produceren beide creatieleden hetzelfde waarneembare gedrag.
-
Consistentie van toegangspatroon: de
HasValueenTryGetValueleden, indien aanwezig, gedragen zich op dezelfde manier als het rechtstreeks controlerenValue.
In het volgende voorbeeld ziet u een aangepast type samenvoeging:
[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
}
Toegangspatroon voor niet-boksen
Een aangepast samenvoegingstype kan eventueel het toegangspatroon voor niet-boksen implementeren om sterk getypte toegang tot waarde-type gevallen mogelijk te maken zonder boksen tijdens patroonkoppeling. Voor dit patroon is het volgende vereist:
- Een
HasValueeigenschap van het typebooldat retourneerttruewanneerValuedat nietnullis. - Een
TryGetValuemethode voor elk casetype dat de waarde retourneertboolen levert via eenoutparameter.TryGetValueretourneerttruealleen wanneerValueeen niet-null-waarde van dat casetype is. Hetouttype van de parameter is id-converteerbaar naar het casetype of naar het onderliggende waardetype wanneer het casetype een null-waardetype is.
[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
}
Voor patroonkoppeling roept de compiler aan TryGetValue op type-patrooncontroles (zoals union is T) en HasValue voor null-patrooncontroles (zoals union is null), om boksen voor waarde-type gevallen te voorkomen. Elk lid is van toepassing op een eigen patroontype: geen van beide is een terugval voor de andere. Wanneer een lid ontbreekt, controleert de compiler in plaats daarvan de Value eigenschap voor dat patroon. Zie Hoe de compiler code genereert voor patroonkoppeling.
Unielidproviders
Een samenvoegingstype kan de leden van de union delegeren aan een openbare geneste IUnionMembers interface die het rechtstreeks bevat en implementeert. Deze interface is de provider van union member. De compiler vindt union-leden alleen op de providerinterface, inclusief overgenomen leden. Leden die alleen zijn gedeclareerd voor het type union zelf, worden niet gebruikt als leden van de vereniging.
Wanneer u een union member provider gebruikt, moet de interface deze vereiste leden declareren:
-
Statische
Createmethoden: één voor elk casetype, met één parameter en een retourtype identity-convertibel naar het samenvoegtype. Met deze methoden worden uw casetypen vastgesteld. -
Valueeigenschap: Een openbareobjecteigenschap ofobject?eigenschap met eengetaccessor die de ingesloten waarde retourneert.
U kunt deze leden desgewenst declareren op de interface, zodat de compiler efficiëntere patroonkoppelingscode genereert:
-
TryGetValuemethoden: één voor elk casetype, die wordt geretourneerdboolmet eenoutparameter van het casetype. -
HasValueeigenschap: Een openbarebooleigenschap met eengettoegangsfunctie die terugkeerttruewanneerValuedat nietnullhet is.
Hoe de compiler code genereert voor patroonkoppeling: TryGetValue en HasValue toepassen op verschillende soorten patronen, is geen van beide een terugval voor de andere:
- Voor een typepatroon, zoals
union is T, roeptTryGetValue(out T value)de compiler aan wanneer deze wordt gedeclareerd, waarbij de waarde wordt geëxtraheerd en het patroon hierop wordt toegepast zonder boksen. Anders past de compiler het patroon toe op deValueeigenschap, waarmee een runtimetypecontroleTwordt uitgevoerd en de waarde kan worden ingeschakeld wanneerThet een waardetype is. - Voor een null-patroon, zoals
union is null, roeptHasValuede compiler aan wanneer deze wordt gedeclareerd om te testen of de samenvoeging een waarde bevat. Anders past de compiler het null-patroon rechtstreeks toe op deValueeigenschap.
Elk lid is onafhankelijk optioneel: zonder TryGetValue, typepatronen gebruiken Value; zonder HasValue, null-patronen gebruiken Value. Door een van beide leden te declareren, kan de compiler efficiëntere, sterk getypte code genereren voor dat patroontype:
[System.Runtime.CompilerServices.Union]
public struct Outcome<T> : Outcome<T>.IUnionMembers
{
private readonly object? _value;
private Outcome(object? value) => _value = value;
public interface IUnionMembers
{
static Outcome<T> Create(T? value) => new(value);
static Outcome<T> Create(Exception? value) => new(value);
object? Value { get; }
// Optional but recommended: TryGetValue enables efficient pattern matching
bool TryGetValue(out T value);
bool TryGetValue(out Exception value);
}
object? IUnionMembers.Value => _value;
public bool TryGetValue(out T value)
{
if (_value is T t)
{
value = t;
return true;
}
value = default!;
return false;
}
public bool TryGetValue(out Exception value)
{
if (_value is Exception e)
{
value = e;
return true;
}
value = default!;
return false;
}
}
Unielidproviders zijn handig wanneer het union-type een privéconstructor nodig heeft of wanneer voor de aanmaaklogica een fabriekspatroon is vereist, zoals bij record class uniontypen.
Op klassen gebaseerde samenvoegtypen
Een klasse kan ook een samenvoegtype zijn. Dit type samenvoeging is handig wanneer u verwijzings-semantiek of overname nodig hebt:
[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",
};
}
Voor op klassen gebaseerde samenvoegingen komt het null patroon overeen met zowel een null-verwijzing als een null-verwijzing Value.
C#-taalspecificatie
Zie de functiespecificatie van Unions voor meer informatie.