wake-up-neo.com

Verwenden Sie Case / Switch und GetType, um das Objekt zu bestimmen

Mögliches Duplikat:
C # - Gibt es eine bessere Alternative zum Einschalten?

Wenn Sie switch für einen Objekttyp festlegen möchten, wie können Sie dies am besten tun?

Code-Auszug

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;
    }
}

Ich weiß, dass das nicht so funktioniert, aber ich habe mich gefragt, wie Sie das lösen können. Ist eine if/else - Anweisung in diesem Fall angemessen?

Oder verwenden Sie den Schalter und fügen dem Typ .ToString() hinzu?

136
user29964

Wenn ich wirklich nach Objekttyp switch müsste, würde ich .ToString() verwenden. Ich würde es jedoch um jeden Preis vermeiden: IDictionary<Type, int> wird es viel besser machen, Besucher könnte ein Overkill sein, aber sonst ist es immer noch eine perfekte Lösung.

73
Anton Gogolev

Dies löst Ihr Problem nicht direkt, da Sie Ihre eigenen benutzerdefinierten Typen einschalten möchten. Für andere, die nur integrierte Typen einschalten möchten, können Sie jedoch den TypeCode verwenden Aufzählung:

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

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

Im MSDN-Blog-Beitrag Viele Fragen: Typ einschalten finden Sie einige Informationen darüber, warum . NET bietet keine Einschaltarten.

Wie üblich gibt es immer Problemumgehungen.

Dieser gehört mir nicht, aber leider habe ich die Quelle verloren. Es macht das Einschalten von Typen möglich, aber ich persönlich finde es ziemlich umständlich (die Wörterbuchidee ist besser):

  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;
      }
  }

Verwendung:

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

Ich würde nur eine if-Anweisung verwenden. In diesem Fall:

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

Der andere Weg dies zu tun ist:

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

Das erste Beispiel gilt nur für exakte Typen, wobei letztere auch auf Vererbung prüfen.

24
David Wengier

Ich habe das gleiche Problem und bin auf diesen Beitrag gestoßen. Ist das, was mit dem IDictionary-Ansatz gemeint ist:

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;
    }
}

Wenn ja, kann ich nicht sagen, dass ich ein Fan davon bin, die Zahlen im Wörterbuch mit den case-Anweisungen in Einklang zu bringen.

Dies wäre ideal, aber die Wörterbuchreferenz bringt es zum Erliegen:

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;
    }
}

Gibt es eine andere Implementierung, die ich übersehen habe?

23
bjaxbjax

Du kannst das:

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

Das wäre zwar eleganter, ist aber möglicherweise nicht so effizient wie einige der anderen Antworten hier.

12

Du kannst das:

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

Es ist klar und einfach. Es ist ein bisschen langsamer als irgendwo das Wörterbuch zwischenzuspeichern. Aber für viel Code ist das sowieso egal.

9
nreyntje

Ein Ansatz besteht darin, NodeDTO eine rein virtuelle GetNodeType () -Methode hinzuzufügen und diese in den Nachkommen zu überschreiben, sodass jeder Nachkomme den tatsächlichen Typ zurückgibt.

7
sharptooth

Je nachdem, was Sie in der switch-Anweisung tun, lautet die richtige Antwort Polymorphismus. Fügen Sie einfach eine virtuelle Funktion in die Schnittstelle/Basisklasse ein und überschreiben Sie sie für jeden Knotentyp.

4
Jason Coyne

Ich denke das ist besser:

  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

Eigentlich bevorzuge ich den Ansatz, der hier als Antwort gegeben wird: Gibt es eine bessere Alternative, um den Typ einzuschalten?

Es gibt jedoch ein gutes Argument dafür, keine Typvergleichsmethoden in einer objektorientierten Sprache wie C # zu implementieren. Alternativ können Sie mithilfe der Vererbung zusätzliche erforderliche Funktionen erweitern und hinzufügen.

Dieser Punkt wurde in den Kommentaren des Autoren-Blogs hier diskutiert: http://blogs.msdn.com/b/jaredpar/archive/2008/05/16/switching-on-types.aspx#8553535 =

Ich fand dies einen äußerst interessanten Punkt, der meine Herangehensweise in einer ähnlichen Situation veränderte und hoffe nur, dass dies anderen hilft.

Mit freundlichen Grüßen, Wayne

0
Wayne Phipps