Vorgehensweise: Sicheres Umwandeln mit Musterabgleich und den Operatoren „is“ und „as“How to safely cast by using pattern matching and the is and as operators

Da Objekte polymorph sind, ist es möglich, dass eine Variable eines Basisklassentyps einen abgeleiteten Typ enthalten kann.Because objects are polymorphic, it's possible for a variable of a base class type to hold a derived type. Für den Zugriff auf die Instanzmember des abgeleiteten Typs ist es erforderlich, dass Sie den Wert wieder in den abgeleiteten Typ umwandeln.To access the derived type's instance members, it's necessary to cast the value back to the derived type. Allerdings entsteht durch eine Umwandlung das Risiko, eine InvalidCastException-Ausnahme auszulösen.However, a cast creates the risk of throwing an InvalidCastException. C# stellt Musterabgleich-Anweisungen bereit, die eine Umwandlung unter der Bedingung ausführen, dass sie erfolgreich sein wird.C# provides pattern matching statements that perform a cast conditionally only when it will succeed. C# bietet außerdem die Operatoren is und as, um zu testen, ob ein Wert einen bestimmten Typ aufweist.C# also provides the is and as operators to test if a value is of a certain type.

Das folgende Beispiel zeigt die Verwendung der is-Anweisung zum Musterabgleich:The following example shows how to use the pattern matching is statement:

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

class Program
{
    static void Main(string[] args)
    {
        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);
        // Output:
        // I am an animal.
        // SuperNova is not a Mammal
    }

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

Im vorhergehenden Beispiel werden einige Features der Syntax für den Musterabgleich veranschaulicht.The preceding sample demonstrates a few features of pattern matching syntax. Die if (a is Mammal m)-Anweisung kombiniert den Test mit einer Initialisierungszuweisung.The if (a is Mammal m) statement combines the test with an initialization assignment. Die Zuweisung tritt nur auf, wenn der Test erfolgreich ist.The assignment occurs only when the test succeeds. Die Variable m befindet sich nur im Bereich der eingebetteten if-Anweisung, dem sie zugewiesen wurde.The variable m is only in scope in the embedded if statement where it has been assigned. Sie können in der gleichen Methode später nicht auf m zugreifen.You cannot access m later in the same method. Das vorstehende Beispiel zeigt auch, wie der as-Operator zum Konvertieren eines Objekts in einen bestimmten Typ verwendet wird.The preceding example also shows how to use the as operator to convert an object to a specified type.

Sie können mithilfe der gleichen Syntax testen, ob ein Nullable-Werttyp einen Wert aufweist, wie im folgenden Beispiel gezeigt:You can also use the same syntax for testing if a nullable value type has a value, as shown in the following example:

class Program
{
    static void Main(string[] args)
    {
        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(System.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(System.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;
        }
    }
}

Im vorhergehenden Beispiel werden weitere Features des Musterabgleichs veranschaulicht, die mit Konvertierungen verwendet werden können.The preceding sample demonstrates other features of pattern matching to use with conversions. Sie können eine Variable für das NULL-Muster prüfen, indem Sie spezifisch nach dem null-Wert sehen.You can test a variable for the null pattern by checking specifically for the null value. Wenn der Laufzeitwert der Variable null ist, gibt eine is-Anweisung, die nach einem Typ prüft, immer false zurück.When the runtime value of the variable is null, an is statement checking for a type always returns false. Die is-Anweisung für den Musterabgleich lässt keinen Nullable-Typ für den Wert zu, z.B. int? oder Nullable<int>, jedoch können Sie nach jedem anderen Werttyp prüfen.The pattern matching is statement doesn't allow a nullable value type, such as int? or Nullable<int>, but you can test for any other value type. Die is-Muster aus dem vorherigen Beispiel sind nicht auf die Nullable-Werttypen beschränkt.The is patterns from the preceding example are not limited to the nullable value types. Sie können diese Muster auch verwenden, um zu testen, ob eine Variable eines Verweistyps über einen Wert oder verfügt oder null ist.You can also use those patterns to test if a variable of a reference type has a value or it's null.

Im vorangegangenen Beispiel wird auch gezeigt, wie Sie das Typmuster in einer switch-Anweisung verwenden, bei der die Variable einen von vielen verschiedenen Typen aufweisen kann.The preceding sample also shows how you use the type pattern in a switch statement where the variable may be one of many different types.

Wenn Sie testen möchten, ob eine Variable einen bestimmten Typ aufweist, Sie aber keine neue Variable zuweisen möchten, können Sie die Operatoren is und as für Verweistypen und Nullable-Werttypen verwenden.If you want to test if a variable is a given type, but not assign it to a new variable, you can use the is and as operators for reference types and nullable value types. Im folgenden Code wird veranschaulicht, wie Sie die Anweisungen is und as verwenden, die Teil der C#-Sprache waren, bevor der Musterabgleich eingeführt wurde, um zu überprüfen, ob eine Variable einen bestimmten Typ aufweist:The following code shows how to use the is and as statements that were part of the C# language before pattern matching was introduced to test if a variable is of a given type:

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

class Program
{
    static void Main(string[] args)
    {
        // Use the is operator to verify the type.
        // before performing a cast.
        Giraffe g = new Giraffe();
        UseIsOperator(g);

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

        // Use the as operator to test
        // an incompatible type.
        SuperNova sn = new SuperNova();
        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 != 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 != null)
        {
            Console.WriteLine(j);
        }
        else
        {
            Console.WriteLine("Could not convert " + val.ToString());
        }
    }
}

Wie Sie durch Vergleichen dieses Codes mit dem Code für den Musterabgleich sehen können, stellt die Syntax für den Musterabgleich robustere Features bereit, indem der Test und die Zuweisung in einer einzelnen Anweisung kombiniert werden.As you can see by comparing this code with the pattern matching code, the pattern matching syntax provides more robust features by combining the test and the assignment in a single statement. Verwenden Sie nach Möglichkeit die Syntax für den Musterabgleich.Use the pattern matching syntax whenever possible.