108 votes

Switch case sur le type c#

Possible Duplicate:
C# - Y a-t-il une meilleure alternative à ceci pour 'switch on type'?

Bonjour supposons que j'ai un gros if/else sur le type de classe. Y a-t-il un moyen de le faire avec un switch case ?

Exemple :

function test(object obj)
{
if(obj is WebControl)
{

}else if(obj is TextBox)
{

}
else if(obj is ComboBox)
{

}

etc ...

J'aimerais créer quelque chose comme

switch(obj)
{
case is TextBox:
break;
case is ComboBox:
break;

}

}

174voto

Steve Points 18193

Mise à jour C# 7

Oui : Source

switch(shape)
{
    case Circle c:
        WriteLine($"cercle avec un rayon de {c.Radius}");
        break;
    case Rectangle s when (s.Length == s.Height):
        WriteLine($"{s.Length} x {s.Height} carré");
        break;
    case Rectangle r:
        WriteLine($"{r.Length} x {r.Height} rectangle");
        break;
    default:
        WriteLine("");
        break;
    case null:
        throw new ArgumentNullException(nameof(shape));
}

Avant C# 7

Non.

http://blogs.msdn.com/b/peterhal/archive/2005/07/05/435760.aspx

Nous recevons de nombreuses demandes d'ajouts au langage C# et aujourd'hui, je vais parler de l'une des plus courantes : le commutateur de type. Le commutateur de type semble être une fonctionnalité assez utile et simple : Ajouter une construction semblable à un commutateur qui bascule sur le type de l'expression, plutôt que sur la valeur. Cela pourrait ressembler à ceci :

switch typeof(e) { 
        case int:    ... break; 
        case string: ... break; 
        case double: ... break; 
        default:     ... break; 
}

Ce genre de déclaration serait extrêmement utile pour ajouter un dispatch de méthode virtuelle sur une hiérarchie de types disjoints, ou sur une hiérarchie de types contenant des types que vous ne possédez pas. En voyant un exemple comme celui-ci, vous pourriez facilement en conclure que la fonctionnalité serait simple et utile. Cela pourrait même vous faire penser "Pourquoi ces maudits concepteurs du langage C# ne facilitent-ils pas ma vie en ajoutant cette fonctionnalité simple et gain de temps?"

Malheureusement, comme de nombreuses fonctionnalités 'simples' de langage, le commutateur de type n'est pas aussi simple qu'il n'y paraît. Les problèmes commencent lorsque vous regardez un exemple plus significatif, et tout aussi important, comme celui-ci :

class C {}
interface I {}
class D : C, I {}

switch typeof(e) {
case C: … break;
case I: … break;
default: … break;
}

Lien : https://blogs.msdn.microsoft.com/peterhal/2005/07/05/many-questions-switch-on-type/

62voto

cdiggins Points 5549

Le code suivant fonctionne plus ou moins comme on s'attendrait à ce qu'un type-switch ne regarde que le type réel (par exemple, ce qui est retourné par GetType()).

public static void TestTypeSwitch()
{
    var ts = new TypeSwitch()
        .Case((int x) => Console.WriteLine("int"))
        .Case((bool x) => Console.WriteLine("bool"))
        .Case((string x) => Console.WriteLine("string"));

    ts.Switch(42);     
    ts.Switch(false);  
    ts.Switch("hello"); 
}

Voici la machinerie nécessaire pour que cela fonctionne.

public class TypeSwitch
{
    Dictionary> matches = new Dictionary>();
    public TypeSwitch Case(Action action) { matches.Add(typeof(T), (x) => action((T)x)); return this; } 
    public void Switch(object x) { matches[x.GetType()](x); }
}

28voto

Timothy Khouri Points 14640

Oui, vous pouvez passer au nom...

switch (obj.GetType().Name)
{
    case "TextBox":...
}

15voto

Enigmativity Points 26345

Voici une option qui reste aussi fidèle que possible à l'exigence de l'OP de pouvoir basculer sur le type. Si vous plissez assez fort les yeux, cela ressemble presque à une déclaration de commutation réelle.

Le code d'appel ressemble à ceci :

var @switch = this.Switch(new []
{
    this.Case(x => { /* Code WebControl ici */ }),
    this.Case(x => { /* Code TextBox ici */ }),
    this.Case(x => { /* Code ComboBox ici */ }),
});

@switch(obj);

Le x dans chaque lambda ci-dessus est fortement typé. Aucun cast nécessaire.

Et pour que cette magie fonctionne, vous avez besoin de ces deux méthodes :

private Action Switch(params Func[] tests)
{
    return o =>
    {
        var @case = tests
            .Select(f => f(o))
            .FirstOrDefault(a => a != null);

        if (@case != null)
        {
            @case();
        }
    };
}

private Func Case(Action action)
{
    return o => o is T ? (Action)(() => action((T)o)) : (Action)null;
}

Cela fait presque venir les larmes aux yeux, n'est-ce pas ?

Néanmoins, ça fonctionne. Profitez-en.

11voto

La chose la plus simple à faire pourrait être d'utiliser la dynamique, c'est-à-dire que vous définissez les méthodes simples comme dans la réponse de Yuval Peled :

void Test(WebControl c)
{
...
}

void Test(ComboBox c)
{
...
}

Ensuite, vous ne pouvez pas appeler directement Test(obj), car la résolution de surcharge est effectuée au moment de la compilation. Vous devez attribuer votre objet à un dynamique puis appeler la méthode Test :

dynamic dynObj = obj;
Test(dynObj);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X