web-dev-qa-db-fra.com

Changer le cas sur le type c #

Duplicate possible:
C # - Existe-t-il une meilleure alternative que celle-ci pour "activer le type"?

Bonjour, supposons que je reçois un gros si/autre sur le type de classe. est-il possible de le faire avec un boîtier de commutateur?

Exemple :

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

}else if(obj is TextBox)
{

}
else if(obj is ComboBox)
{

}

etc ...

Je voudrais créer quelque chose comme

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

}

}

56
Cédric Boivin

Non.

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

Nous recevons beaucoup de demandes d'ajouts au langage C # et aujourd'hui, je vais parler de l'un des plus courants: le type de commutation. Activer le type ressemble à une fonctionnalité plutôt utile et directe: ajoutez une construction semblable à un commutateur qui active le type de l'expression plutôt que la valeur. Cela pourrait ressembler à ceci:

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

Ce type d'instruction serait extrêmement utile pour l'ajout de méthodes virtuelles telles que la répartition sur une hiérarchie de types disjoint 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 déduire que la fonctionnalité serait simple et utile. Cela pourrait même vous faire penser "Pourquoi ces concepteurs de langage C # # * &% $ paresseux ne me facilitent-ils pas la vie et ajoutent-ils cette fonctionnalité de langage simple et rapide?"

Malheureusement, à l'instar de nombreuses fonctionnalités de langage simples, le changement de type n'est pas aussi simple qu'il y paraît. Les problèmes commencent lorsque vous regardez un exemple plus significatif, et non moins 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/

Mise à jour C # 7

Oui: Source

switch(shape)
{
    case Circle c:
        WriteLine($"circle with radius {c.Radius}");
        break;
    case Rectangle s when (s.Length == s.Height):
        WriteLine($"{s.Length} x {s.Height} square");
        break;
    case Rectangle r:
        WriteLine($"{r.Length} x {r.Height} rectangle");
        break;
    default:
        WriteLine("<unknown shape>");
        break;
    case null:
        throw new ArgumentNullException(nameof(shape));
}
66
Steve

Le code suivant fonctionne plus ou moins comme on pourrait s'y attendre si un commutateur de type 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 les machines nécessaires pour le faire fonctionner.

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

Oui, vous pouvez activer le nom ...

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

Voici une option qui reste vraie. Je pourrais répondre aux exigences du PO pour pouvoir activer le type. Si vous louchez suffisamment fort, cela ressemble presque à une véritable déclaration de commutateur.

Le code d'appel ressemble à ceci:

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

@switch(obj);

Le x de chaque lambda ci-dessus est fortement typé. Aucun casting requis.

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

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

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

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

Apporte presque des larmes à vos yeux, non?

Néanmoins, ça marche. Prendre plaisir.

13
Enigmativity

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 la surcharge est effectuée au moment de la compilation. Vous devez affecter votre objet à une dynamique, puis appeler la méthode Test:

dynamic dynObj = obj;
Test(dynObj);
9