Utilisation de Case / Switch et GetType pour déterminer l'objet [dupliquer]

possible Duplicate:

C# - y a-t-il une meilleure alternative que celle de "switch on type"?

Si vous voulez switch sur un type d'objet, quelle est la meilleure façon de le faire?

"1519160920 extrait de Code",
private int GetNodeType(NodeDTO node)
{
    switch (node.GetType())
    { 
        case typeof(CasusNodeDTO):
            return 1;
        case typeof(BucketNodeDTO):
            return 3;
        case typeof(BranchNodeDTO):
            return 0;
        case typeof(LeafNodeDTO):
            return 2;
        default:
            return -1;
    }
}

je sais que ça ne marche pas comme ça, mais je me demandais comment tu pouvais résoudre ça. Est un if/else déclaration appropriée dans ce cas?

ou utilisez-vous l'interrupteur et ajoutez .ToString() au type?

122
demandé sur Community 2009-04-02 13:07:04

11 réponses

Si je vraiment devait switch sur le type d'objet, j'utiliserais .ToString() . Cependant, je l'éviterais à tout prix: IDictionary<Type, int> fera beaucoup mieux, visiteur peut-être un surmenage, mais autrement il est encore une solution parfaitement fine.

66
répondu Anton Gogolev 2009-04-02 09:10:32

cela ne résoudra pas directement votre problème que vous voulez activer sur vos propres types définis par l'utilisateur, mais pour le bénéfice d'autres qui veulent seulement activer sur les types intégrés, vous pouvez utiliser le TypeCode enumeration:

switch (Type.GetTypeCode(node.GetType()))
{
    case TypeCode.Decimal:
        // Handle Decimal
        break;

    case TypeCode.Int32:
        // Handle Int32
        break;
     ...
}
91
répondu Ashley 2013-09-16 10:53:06

Dans MSDN blog de Nombreuses Questions: sur le switch de type , quelques informations sur les raisons de .NET ne fournit pas de commutation sur les types.

comme d'habitude - workarounds existe toujours.

celui-ci n'est pas à moi, mais malheureusement j'ai perdu la source. Cela permet de changer de type, mais je pense personnellement que c'est assez embarrassant (l'idée du dictionnaire est meilleure):

  public class Switch
  {
      public Switch(Object o)
      {
          Object = o;
      }

      public Object Object { get; private set; }
  }


  /// <summary>
  /// Extensions, because otherwise casing fails on Switch==null
  /// </summary>
  public static class SwitchExtensions
  {
      public static Switch Case<T>(this Switch s, Action<T> a)
            where T : class
      {
          return Case(s, o => true, a, false);
      }

      public static Switch Case<T>(this Switch s, Action<T> a,
           bool fallThrough) where T : class
      {
          return Case(s, o => true, a, fallThrough);
      }

      public static Switch Case<T>(this Switch s,
          Func<T, bool> c, Action<T> a) where T : class
      {
          return Case(s, c, a, false);
      }

      public static Switch Case<T>(this Switch s,
          Func<T, bool> c, Action<T> a, bool fallThrough) where T : class
      {
          if (s == null)
          {
              return null;
          }

          T t = s.Object as T;
          if (t != null)
          {
              if (c(t))
              {
                  a(t);
                  return fallThrough ? s : null;
              }
          }

          return s;
      }
  }

Utilisation:

 new Switch(foo)
     .Case<Fizz>
         (action => { doingSomething = FirstMethodCall(); })
     .Case<Buzz>
         (action => { return false; })
39
répondu Arnis Lapsa 2014-02-21 15:47:54

j'utiliserais juste une instruction if. Dans ce cas:

Type nodeType = node.GetType();
if (nodeType == typeof(CasusNodeDTO))
{
}
else ... 

L'autre façon de le faire est:

if (node is CasusNodeDTO)
{
}
else ...

le premier exemple est vrai pour les types exacts seulement, où le dernier contrôle pour l'héritage aussi.

24
répondu David Wengier 2014-03-26 19:09:00

je suis confronté au même problème et suis tombé sur ce post. Est-ce que c'est ce qu'on entend par l'approche iDictionnaire:

Dictionary<Type, int> typeDict = new Dictionary<Type, int>
{
    {typeof(int),0},
    {typeof(string),1},
    {typeof(MyClass),2}
};

void Foo(object o)
{
    switch (typeDict[o.GetType()])
    {
        case 0:
            Print("I'm a number.");
            break;
        case 1:
            Print("I'm a text.");
            break;
        case 2:
            Print("I'm classy.");
            break;
        default:
            break;
    }
}

si c'est le cas, je ne peux pas dire que je suis un fan de concilier les nombres dans le dictionnaire avec les déclarations de cas.

ce serait idéal mais la référence au dictionnaire le tue:

void FantasyFoo(object o)
{
    switch (typeDict[o.GetType()])
    {
        case typeDict[typeof(int)]:
            Print("I'm a number.");
            break;
        case typeDict[typeof(string)]:
            Print("I'm a text.");
            break;
        case typeDict[typeof(MyClass)]:
            Print("I'm classy.");
            break;
        default:
            break;
    }
}

y a-t-il une autre implémentation que j'ai oubliée?

22
répondu bjaxbjax 2009-12-02 20:17:25

Vous pouvez faire ceci:

if (node is CasusNodeDTO)
{
    ...
}
else if (node is BucketNodeDTO)
{
    ...
}
...

Tandis que, plus élégante, c'est peut-être pas aussi efficace que d'autres réponses ici.

11
répondu Dave Van den Eynde 2009-04-02 09:12:33

Vous pouvez faire ceci:

function void PrintType(Type t) {
 var t = true;
 new Dictionary<Type, Action>{
   {typeof(bool), () => Console.WriteLine("bool")},
   {typeof(int),  () => Console.WriteLine("int")}
 }[t.GetType()]();
}

c'est clair et facile. C'est un peu plus lent que de cacher le dictionnaire quelque part.. mais pour beaucoup de code cela n'a pas d'importance de toute façon..

8
répondu nreyntje 2010-08-04 00:52:52

une approche consiste à ajouter une méthode pure virtual GetNodeType() pour NodeDTO et la surcharger dans les descendants de sorte que chaque descendant retourne le type réel.

7
répondu sharptooth 2009-04-02 09:13:11

selon ce que vous faites dans la déclaration switch, la bonne réponse est polymorphisme. Il suffit de mettre une fonction virtuelle dans la classe interface/base et de surcharger pour chaque type de noeud.

4
répondu Jason Coyne 2009-04-02 14:08:20

j'utiliserais la chaîne (nom) en haut de l'interrupteur:

  private int GetNodeType(NodeDTO node)
            {
                    switch (node.GetType().Name)
                    { 
                            case "CasusNodeDTO":
                                    return 1;
                                    break;
                            case "BucketNodeDTO":
                                    return 3;
                                    break;
                           // ...

                            default:
                                    return -1;
                                    break;
                    }
            }
0
répondu Program.X 2009-04-02 09:10:57

je préfère en fait l'approche donnée comme la réponse ici: Est-il une meilleure alternative que de ce "de type"?

il y a cependant un bon argument sur le fait de ne pas mettre en œuvre n'importe quel type de methids de comparaison dans un langage orienté objet comme C#. Vous pouvez comme alternative étendre et ajouter des fonctionnalités supplémentaires requises en utilisant l'héritage.

ce point a été discuté dans les commentaires des auteurs blog ici: http://blogs.msdn.com/b/jaredpar/archive/2008/05/16/switching-on-types.aspx#8553535

j'ai trouvé ce point extrêmement intéressant qui a changé mon approche dans une situation similaire et j'espère seulement que cela aide les autres.

Salutations, Wayne

0
répondu Wayne Phipps 2017-05-23 12:34:39