Использование Case / Switch и GetType для определения объекта

Возможный дубликат:
C # – Есть ли лучшая альтернатива этому, чтобы «включить тип»?

Если вы хотите switch тип объекта, что это лучший способ сделать это?

Фрагмент кода

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

Я знаю, что это не работает, но мне было интересно, как вы могли это решить. Является ли утверждение if/else подходящим в этом случае?

Или вы используете переключатель и добавляете .ToString() к типу?

Если мне действительно пришлось switch тип объекта, я бы использовал .ToString() . Тем не менее, я бы избегал этого любой ценой: IDictionary будет намного лучше, посетитель может быть излишним, но в остальном это все еще прекрасное решение.

Это не решит вашу проблему напрямую, так как вы хотите использовать свои собственные пользовательские типы, но для других, которые хотят только включить встроенные типы, вы можете использовать перечисление TypeCode :

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

В сообщении блога MSDN Многие вопросы: тип включения – это некоторая информация о том, почему .NET не обеспечивает включение типов.

Как обычно – обходные пути всегда существуют.

Этот не мой, но, к сожалению, я потерял источник. Это делает возможным включение типов, но я лично считаю, что это довольно неудобно (идея словаря лучше):

  public class Switch { public Switch(Object o) { Object = o; } public Object Object { get; private set; } } ///  /// Extensions, because otherwise casing fails on Switch==null ///  public static class SwitchExtensions { public static Switch Case(this Switch s, Action a) where T : class { return Case(s, o => true, a, false); } public static Switch Case(this Switch s, Action a, bool fallThrough) where T : class { return Case(s, o => true, a, fallThrough); } public static Switch Case(this Switch s, Func c, Action a) where T : class { return Case(s, c, a, false); } public static Switch Case(this Switch s, Func c, Action 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; } } 

Применение:

  new Switch(foo) .Case (action => { doingSomething = FirstMethodCall(); }) .Case (action => { return false; }) 

Я бы просто использовал оператор if. В этом случае:

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

Другой способ сделать это:

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

Первый пример верен только для точных типов, где последний также проверяет наследование.

Я столкнулся с той же проблемой и столкнулся с этим сообщением. Это то, что подразумевается под подходом IDictionary:

 Dictionary typeDict = new Dictionary { {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; } } 

Если это так, я не могу сказать, что я поклонник согласования чисел в словаре с утверждениями case.

Это было бы идеально, но словарная ссылка убивает:

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

Есть ли другая реализация, которую я забыл?

Вы можете сделать это:

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

Хотя это было бы более элегантно, возможно, это не так эффективно, как некоторые другие ответы здесь.

Вы можете сделать это:

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

Это понятно и легко. Это немного медленнее, чем кеширование словаря где-то .. но для большого количества кода это не имеет значения.

Один из подходов состоит в том, чтобы добавить чистый виртуальный метод GetNodeType () в NodeDTO и переопределить его в потомках, чтобы каждый потомок возвращал фактический тип.

В зависимости от того, что вы делаете в инструкции switch, правильным ответом является polymorphism. Просто поместите виртуальную функцию в интерфейс / базовый class и переопределите для каждого типа узла.

Я бы использовал строку (Name) в верхней части переключателя:

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

Я на самом деле предпочитаю подход, данный как ответ здесь: есть ли более эффективная альтернатива этому, чтобы «включить тип»?

Тем не менее, есть хороший аргумент в том, что не следует применять какие-либо типы сравнения в объектно-ориентированном языке, таком как C #. Вы могли бы в качестве альтернативы расширить и добавить дополнительные требуемые функции, используя наследование.

Этот момент обсуждался в комментариях авторов блога здесь: http://blogs.msdn.com/b/jaredpar/archive/2008/05/16/switching-on-types.aspx#8553535

Я нашел это чрезвычайно интересным моментом, который изменил мой подход в подобной ситуации и только надеюсь, что это помогает другим.

С уважением, Уэйн

  • Java: если vs. Switch
  • Несколько случаев в инструкции switch
  • Контроль не может провалиться с одного ярлыка случая
  • Почему этот переключатель на корпусе типа считается запутанным?
  • идея выбора переключателя / образца
  • Какова относительная разница в производительности if / else по сравнению с оператором switch в Java?
  • Есть ли лучшая альтернатива этому, чтобы «включить тип»?
  • Случайный охват шкафа
  • Если против скорости переключения
  • Как выбрать диапазон значений в инструкции switch?
  • Использование двух значений для одного оператора case switch
  • Давайте будем гением компьютера.