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

StackOverflow https://stackoverflow.com/questions/708911

Вопрос

Возможный дубликат:
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<Type, int> сделаю намного лучше, посетитель может быть излишним, но в остальном это прекрасное решение.

Другие советы

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

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

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

В сообщении блога MSDN Много вопросов:Тип включения есть некоторая информация о том, почему .СЕТЬ не обеспечивает переключение типов.

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

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

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

Использование:

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

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

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

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

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

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

Я столкнулся с той же проблемой и наткнулся на этот пост.Это то, что подразумевается под подходом 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;
    }
}

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

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

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<Type, Action>{
   {typeof(bool), () => Console.WriteLine("bool")},
   {typeof(int),  () => Console.WriteLine("int")}
 }[t.GetType()]();
}

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top