Hur man på ett säkert sätt gjuter med hjälp av mönstermatchning och is och som operatorer

Eftersom objekt är polymorfa kan en variabel av en basklasstyp innehålla en härledd typ. För att få åtkomst till den härledda typens instansmedlemmar är det nödvändigt att återställa värdet till den härledda typen. En rollbesättning skapar dock risk för att kasta en InvalidCastException. C# innehåller mönstermatchningsinstruktioner som endast utför en gjuten villkorligt när den lyckas. C# tillhandahåller även is - och as-operatorerna för att testa om ett värde är av en viss typ.

I följande exempel visas hur du använder instruktionen för mönstermatchning is :

var g = new Giraffe();
var a = new Animal();
FeedMammals(g);
FeedMammals(a);
// Output:
// Eating.
// Animal is not a Mammal

SuperNova sn = new SuperNova();
TestForMammals(g);
TestForMammals(sn);

static void FeedMammals(Animal a)
{
    if (a is Mammal m)
    {
        m.Eat();
    }
    else
    {
        // variable 'm' is not in scope here, and can't be used.
        Console.WriteLine($"{a.GetType().Name} is not a Mammal");
    }
}

static void TestForMammals(object o)
{
    // You also can use the as operator and test for null
    // before referencing the variable.
    var m = o as Mammal;
    if (m != null)
    {
        Console.WriteLine(m.ToString());
    }
    else
    {
        Console.WriteLine($"{o.GetType().Name} is not a Mammal");
    }
}
// Output:
// I am an animal.
// SuperNova is not a Mammal

class Animal
{
    public void Eat() { Console.WriteLine("Eating."); }
    public override string ToString()
    {
        return "I am an animal.";
    }
}
class Mammal : Animal { }
class Giraffe : Mammal { }

class SuperNova { }

Föregående exempel visar några funktioner i mönstermatchningssyntax. -instruktionen if (a is Mammal m) kombinerar testet med en initieringstilldelning. Tilldelningen sker endast när testet lyckas. Variabeln m finns bara i omfånget i den inbäddade if instruktionen där den har tilldelats. Du kan inte komma åt m senare i samma metod. Föregående exempel visar också hur du använder operatorn as för att konvertera ett objekt till en angiven typ.

Du kan också använda samma syntax för testning om en nullbar värdetyp har ett värde, som du ser i följande exempel:

int i = 5;
PatternMatchingNullable(i);

int? j = null;
PatternMatchingNullable(j);

double d = 9.78654;
PatternMatchingNullable(d);

PatternMatchingSwitch(i);
PatternMatchingSwitch(j);
PatternMatchingSwitch(d);

static void PatternMatchingNullable(ValueType? val)
{
    if (val is int j) // Nullable types are not allowed in patterns
    {
        Console.WriteLine(j);
    }
    else if (val is null) // If val is a nullable type with no value, this expression is true
    {
        Console.WriteLine("val is a nullable type with the null value");
    }
    else
    {
        Console.WriteLine("Could not convert " + val.ToString());
    }
}

static void PatternMatchingSwitch(ValueType? val)
{
    switch (val)
    {
        case int number:
            Console.WriteLine(number);
            break;
        case long number:
            Console.WriteLine(number);
            break;
        case decimal number:
            Console.WriteLine(number);
            break;
        case float number:
            Console.WriteLine(number);
            break;
        case double number:
            Console.WriteLine(number);
            break;
        case null:
            Console.WriteLine("val is a nullable type with the null value");
            break;
        default:
            Console.WriteLine("Could not convert " + val.ToString());
            break;
    }
}

Föregående exempel visar andra funktioner i mönstermatchning som ska användas med konverteringar. Du kan testa en variabel för null-mönstret genom att specifikt null söka efter värdet. När körningsvärdet för variabeln är nullreturnerar falseen is instruktion som söker efter en typ alltid . Mönstermatchningssatsen is tillåter inte en nullbar värdetyp, till exempel int? eller Nullable<int>, men du kan testa för någon annan värdetyp. Mönstren is från föregående exempel är inte begränsade till de nullbara värdetyperna. Du kan också använda dessa mönster för att testa om en variabel av en referenstyp har ett värde eller om den är null.

Föregående exempel visar också hur du använder typmönstret i en switch -instruktion där variabeln kan vara en av många olika typer.

Om du vill testa om en variabel är en viss typ, men inte tilldelar den till en ny variabel, kan du använda operatorerna is och as för referenstyper och nullbara värdetyper. Följande kod visar hur du använder is - och-instruktioner as som var en del av C#-språket innan mönstermatchning introducerades för att testa om en variabel är av en viss typ:

// Use the is operator to verify the type.
// before performing a cast.
Giraffe g = new();
UseIsOperator(g);

// Use the as operator and test for null
// before referencing the variable.
UseAsOperator(g);

// Use pattern matching to test for null
// before referencing the variable
UsePatternMatchingIs(g);

// Use the as operator to test
// an incompatible type.
SuperNova sn = new();
UseAsOperator(sn);

// Use the as operator with a value type.
// Note the implicit conversion to int? in
// the method body.
int i = 5;
UseAsWithNullable(i);

double d = 9.78654;
UseAsWithNullable(d);

static void UseIsOperator(Animal a)
{
    if (a is Mammal)
    {
        Mammal m = (Mammal)a;
        m.Eat();
    }
}

static void UsePatternMatchingIs(Animal a)
{
    if (a is Mammal m)
    {
        m.Eat();
    }
}

static void UseAsOperator(object o)
{
    Mammal? m = o as Mammal;
    if (m is not null)
    {
        Console.WriteLine(m.ToString());
    }
    else
    {
        Console.WriteLine($"{o.GetType().Name} is not a Mammal");
    }
}

static void UseAsWithNullable(System.ValueType val)
{
    int? j = val as int?;
    if (j is not null)
    {
        Console.WriteLine(j);
    }
    else
    {
        Console.WriteLine("Could not convert " + val.ToString());
    }
}
class Animal
{
    public void Eat() => Console.WriteLine("Eating.");
    public override string ToString() => "I am an animal.";
}
class Mammal : Animal { }
class Giraffe : Mammal { }

class SuperNova { }

Som du kan se genom att jämföra den här koden med mönstermatchningskoden ger syntaxen för mönstermatchning mer robusta funktioner genom att kombinera testet och tilldelningen i en enda instruktion. Använd syntaxen för mönstermatchning när det är möjligt.