web-dev-qa-db-fra.com

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

Duplicate possible:
C # - Existe-t-il une meilleure alternative que celle-ci au "type de commutation"?

Si vous voulez switch sur un type d'objet, quel est le meilleur moyen de le faire?

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 cela ne fonctionne pas de cette façon, mais je me demandais comment résoudre ce problème. Une déclaration if/else est-elle appropriée dans ce cas?

Ou utilisez-vous le commutateur et ajoutez-vous .ToString() au type?

136
user29964

Si je vraiment devais switch sur le type d'objet, j'utiliserais .ToString(). Cependant, je l'éviterais à tout prix: IDictionary<Type, int> ferait beaucoup mieux, visiteur peut-être un excès, mais sinon, c'est toujours une solution parfaite.

73
Anton Gogolev

Cela ne résoudra pas directement votre problème car vous souhaitez activer vos propres types définis par l'utilisateur, mais pour le bénéfice des autres utilisateurs souhaitant uniquement activer les types intégrés, vous pouvez utiliser le type TypeCode énumération:

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

    case TypeCode.Int32:
        // Handle Int32
        break;
     ...
}
107
Ashley

Dans le blog MSDN Nombreuses questions: activez le type contient des informations sur les raisons pour lesquelles . NET ne fournit pas de types de commutation.

Comme d'habitude - les solutions de contournement existent toujours.

Celui-ci ne m'appartient pas, mais malheureusement, j'ai perdu la source. Cela permet de changer de type, mais je trouve personnellement que c'est assez bizarre (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;
      }
  }

Usage:

 new Switch(foo)
     .Case<Fizz>
         (action => { doingSomething = FirstMethodCall(); })
     .Case<Buzz>
         (action => { return false; })
41
Arnis Lapsa

Je voudrais juste utiliser une déclaration si. Dans ce cas:

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

L'autre façon de faire est:

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

Le premier exemple est vrai pour les types exacts uniquement, où ce dernier vérifie également l'héritage.

24
David Wengier

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

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 partisan de la réconciliation des chiffres du dictionnaire avec les instructions de cas.

Ce serait l'idéal mais la référence du 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;
    }
}

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

23
bjaxbjax

Tu peux le faire:

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

Bien que cela soit plus élégant, ce n’est peut-être pas aussi efficace que certaines des autres réponses données ici.

12

Tu peux le faire:

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 c'est facile. C'est un peu plus lent que de mettre le dictionnaire en cache quelque part .. mais pour beaucoup de code cela n'aura pas d'importance de toute façon ..

9
nreyntje

Une approche consiste à ajouter une méthode virtuelle GetNodeType () pure à NodeDTO et à la remplacer dans les descendants afin que chaque descendant renvoie le type réel.

7
sharptooth

Selon ce que vous faites dans l'instruction switch, la bonne réponse est le polymorphisme. Il suffit de mettre une fonction virtuelle dans la classe d’interface/base et de la remplacer pour chaque type de nœud.

4
Jason Coyne

Je pense que c'est mieux:

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

                            default:
                                    return -1;
                                    break;
                    }
            }
0
Program.X

En fait, je préfère l’approche donnée comme réponse ici: Existe-t-il une meilleure alternative que celle-ci pour "activer le type"?

Cependant, il existe un bon argument pour ne pas implémenter de méthode de comparaison de type dans un langage orienté objet comme C #. Vous pouvez également étendre et ajouter des fonctionnalités supplémentaires requises à l'aide de l'héritage.

Ce point a été abordé dans les commentaires du blog des auteurs 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 aidera les autres.

Cordialement, Wayne

0
Wayne Phipps