Partager via


Guide pratique pour caster de manière sécurisée avec des critères spéciaux, ainsi que les opérateurs is et as

Dans la mesure où les objets sont polymorphes, une variable d’un type de classe de base peut contenir un type dérivé. Pour accéder aux membres d’instance du type dérivé, il est nécessaire de réeffectuer un cast de la valeur vers le type dérivé. Toutefois, un cast risque de lever InvalidCastException. C# fournit des instructions relatives aux critères spéciaux, qui effectuent un cast de manière conditionnelle, uniquement en cas de réussite. C# fournit également les opérateurs is et as pour tester l’appartenance d’une valeur à un certain type.

L’exemple suivant montre comment utiliser l’instruction is des critères spéciaux :

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

L’exemple précédent illustre quelques fonctionnalités de la syntaxe relative aux critères spéciaux. L’instruction if (a is Mammal m) combine le test à une assignation d’initialisation. L’assignation n’a lieu qu’en cas de réussite du test. La variable m se trouve uniquement dans l’étendue de l’instruction if incorporée, à laquelle elle a été assignée. Vous ne pouvez pas accéder à m plus tard dans la même méthode. L’exemple précédent montre également comment utiliser l’opérateur as pour convertir un objet en un type spécifié.

Vous pouvez également utiliser la même syntaxe afin de tester l’existence si un type valeur pouvant accepter la valeur Null a une valeur, comme indiqué dans l’exemple de code suivant :

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

L’exemple précédent illustre d’autres fonctionnalités relatives aux critères spéciaux pour les conversions. Vous pouvez tester le modèle null d’une variable en vérifiant spécifiquement la valeur null. Quand la valeur runtime de la variable est null, une instruction is de vérification de type retourne toujours false. L’instruction is relative aux critères spéciaux n’autorise aucun type valeur Nullable, par exemple int? ou Nullable<int>. Toutefois, vous pouvez tester un autre type valeur. Les modèles is de l’exemple précédent ne sont pas limités aux types valeur pouvant accepter la valeur Null. Vous pouvez également utiliser ces modèles pour tester si une variable d’un type référence a une valeur ou s’il s’agit de null.

L’exemple précédent montre également comment utiliser le type de modèle dans une instruction switch où la variable peut avoir plusieurs types différents.

Pour déterminer si une variable a un type donné, mais sans l’assigner pour autant à une nouvelle variable, vous pouvez utiliser les opérateurs is et as pour les types référence et les types valeur pouvant accepter la valeur Null. Le code suivant montre comment utiliser les instructions is et as, qui faisaient partie du langage C# avant l’introduction des critères spéciaux permettant de déterminer l’existence ou non d’un type donné pour une variable :

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

Comme vous pouvez le constater en comparant ce code avec le code utilisant les critères spéciaux, la syntaxe des critères spéciaux fournit des fonctionnalités plus robustes, car elle combine le test et l’assignation dans une seule instruction. Utilisez la syntaxe des critères spéciaux autant que possible.