web-dev-qa-db-fra.com

L'expression de type T ne peut pas être gérée par un motif de type X

J'ai mis à niveau mon projet pour cibler le C # 7 et utilisé Visual Studio 2017 RC pour implémenter la correspondance de modèle dans ma solution. Après cela, des erreurs ont été introduites concernant la correspondance de modèle avec des paramètres génériques.

Considérons le code suivant:

public class Packet
{
}

public class KeepalivePacket : Packet
{
}

public void Send<T>(T packet)
    where T : Packet
{
    if (packet is KeepalivePacket keepalive)
    {
        // Do stuff with keepalive
    }

    switch (packet)
    {
        case KeepalivePacket keepalivePacket:
            // Do stuff with keepalivePacket
            break;
    }
}

L'instruction if et l'instruction case produisent une erreur de compilation.

Une expression de type T ne peut pas être gérée par un motif de type KeepalivePacket

Si je transforme d'abord le paramètre en type object, la correspondance de modèle fonctionne comme prévu. Roslyn marque ensuite le casting à object comme redondant.

if ((object)packet is KeepalivePacket keepalive)
{
    // This works
}

Cette erreur semble s’appliquer uniquement aux paramètres et variables génériques. Roslyn semble ne pas être au courant de ce problème car il recommande de changer le code pour utiliser la correspondance de modèle via un analyseur et me permet d'appliquer le "correctif de code" qui résulte en un code cassé.

22
Alex Wiese

Comme expliqué par Neal Gafter de Microsoft:

Cela ne fonctionne pas parce qu’il n’ya pas de conversion (explicite ou implicite) définie de T vers KeepalivePacket. La mise en correspondance de modèles nécessite l'existence d'une telle conversion, telle qu'elle est définie en termes d'opérateur de conversion, ce qui nécessite l'existence d'une conversion. La spécification de langue et le compilateur conviennent qu'aucune conversion n'existe. Il me semble étrange que la spécification de langage soit définie de sorte qu'aucune conversion (explicite) n'existe ici. Nous allons voir ce que nous pouvons faire à ce sujet. 

Nous n'allons rien faire à ce sujet en C # 7. Vous devrez ajouter une distribution à votre code pour résoudre ce problème. Une fois que nous avons des modèles récursifs, cela peut être plus difficile à contourner. De plus, la règle de langage maladroit qui sous-tend cette question (c’est-à-dire qu’il n’ya pas de conversion de T en KeepalivePacket) n’a pas beaucoup de sens.

Mettre à jour

Cela fonctionne maintenant en C # 7.1

16
Alex Wiese

C # 7.1 supporte cela maintenant. Par exemple, voir "Correspondance de modèle avec les génériques" dans cet article . Vous devrez peut-être ajouter <LangVersion>7.1</LangVersion> ou <LangVersion>latest</LangVersion> à votre fichier de projet. Voir ici pour plus de détails sur la configuration de LangVersion.

2
Nate Cook