方法: パターン マッチング、is 演算子、as 演算子を使用して安全にキャストするHow to: safely cast by using pattern matching is and as operators

オブジェクトはポリモーフィックであるため、基本クラス型の変数で派生を保持できます。Because objects are polymorphic, it's possible for a variable of a base class type to hold a derived type. 派生型のインスタンス メンバーにアクセスするには、値をキャストして派生型に戻す必要があります。To access the derived type's instance members, it's necessary to cast the value back to the derived type. ただし、キャストでは、InvalidCastException がスローされるリスクが生まれます。However, a cast creates the risk of throwing an InvalidCastException. C# には、パターン マッチング ステートメントがあります。これは成功する場合のみという条件でキャストを実行します。C# provides pattern matching statements that perform a cast conditionally only when it will succeed. C# には、値が特定の型であることをテストする is 演算子と as 演算子もあります。C# also provides the is and as operators to test if a value is of a certain type.

注意

この記事の C# 例は、Try.NET インライン コード ランナーとプレイグラウンドで実行されます。The C# examples in this article run in the Try.NET inline code runner and playground. [実行] ボタンを選択すると、対話型ウィンドウで例が実行されます。Select the Run button to run an example in an interactive window. コードを実行したら、コードを変更し、[実行] をもう一度選択して変更後のコードを実行できます。Once you execute the code, you can modify it and run the modified code by selecting Run again. 変更後のコードが対話型ウィンドウで実行されるか、コンパイルできなかった場合、対話型ウィンドウにすべての C# コンパイラ エラー メッセージが表示されます。The modified code either runs in the interactive window or, if compilation fails, the interactive window displays all C# compiler error messages.

次のコードは、パターン マッチング is ステートメントを示しています。The following code demonstrates the pattern matching is statement. メソッド引数をテストし、それが可能な派生型セットの 1 つであるかどうかを判断するメソッドが含まれています。It contains methods that test a method argument to determine if it is one of a possible set of derived types:

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)
    {
        Giraffe g = new Giraffe();
        FeedMammals(g);

        TestForMammals(g);

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

    static void FeedMammals(Animal a)
    {
        // Use the is operator to verify the type
        // before performing a cast.
        if (a is Mammal m)
        {
            m.Eat();
        }
    }

    static void TestForMammals(object o)
    {
        // Alternatively, use the as operator and test for null
        // before referencing the variable.
        if (o is Mammal m)
        {
            Console.WriteLine(m.ToString());
        }
        else
        {
            // variable 'm' is not in scope here, and can't be used.
            Console.WriteLine($"{o.GetType().Name} is not a Mammal");
        }
    }
}

上記のサンプルでは、パターン マッチング構文のいくつかの機能が示されています。The preceding sample demonstrates a few features of pattern matching syntax. if (a is Mammal m) ステートメントと if (o is Mammal m) ステートメントにより、初期化が割り当てられたテストが結合されます。The if (a is Mammal m) and if (o is Mammal m) statements combine the test with an initialization assignment. この割り当ては、テストに成功した場合にのみ行われます。The assignment occurs only when the test succeeds. 変数 m は、それが割り当てられている埋め込み if ステートメントでのみ範囲に入ります。The variable m is only in scope in the embedded if statement where it has been assigned. 後で同じメソッドで m にアクセスすることはできません。You cannot access m later in the same method. 対話型ウィンドウで試してください。Try it in the interactive window.

次のサンプル コードに示されているように、null 許容型に値があるかどうかをテストする目的で同じ構文を使用することもできます。You can also use the same syntax for testing if a nullable type has a value, as shown in the following sample code:

class Program
{
    static void Main(string[] args)
    {
        // Use the as operator with a value type.
        // Note the implicit conversion to int? in 
        // the method body.
        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;
        }
    }
}

上記のサンプルでは、変換で使用するパターン マッチング構文の他の機能が示されています。The preceding sample demonstrates other features of pattern matching to use with conversions. null 値を具体的に探すことで null パターンの変数をテストできます。You can test a variable for the null pattern by checking specifically for the null value. 変数のランタイム値が null のとき、is ステートメントで型を確認すると必ず false が返されます。When the runtime value of the variable is null, an is statement checking for a type always returns false. パターン マッチング is ステートメントでは、int?Nullable<int> など、null 許容値型が許可されませんが、他の値の型についてはテストできます。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.

上記のサンプルでは、変数がさまざまな型の 1 つになる switch ステートメントでパターン マッチング is 式を使用する方法も確認できます。The preceding sample also shows how you use the pattern matching is expression in a switch statement where the variable may be one of many different types.

変数が指定の型かどうかをテストしても、それを新しい変数に割り当てない場合、参照型と null 許容型に対して is 演算子と as 演算子を使用できます。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 types. 次のコードでは、パターン マッチングが導入される前に C# 言語に含まれていた is ステートメントと as ステートメントを使用し、変数が指定の型かどうかをテストする方法が示されています。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());
        }
    }
}

ご覧のとおり、このコードとパターン マッチング コードを比較することで、テストと割り当てが 1 回のステートメントで組み合わされ、パターン マッチング構文がより強固になります。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. 可能な限り、パターン マッチングを使用してください。Use the pattern matching syntax whenever possible.

GitHub リポジトリのコードを見て、これらのサンプルを試すことができます。You can try these samples by looking at the code in our GitHub repository. または、サンプルを zip ファイルとしてダウンロードすることができます。Or you can download the samples as a zip file.