Usando Case / Switch y GetType para determinar el objeto [duplicar]


Posible Duplicado:
C# - ¿Hay una alternativa mejor que esta para 'activar el tipo'?

Si desea switch en un tipo de objeto, ¿cuál es la mejor manera de hacerlo?

Fragmento de código

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

Sé que esto no funciona de esa manera, pero me preguntaba cómo podría resolver esto. ¿Es apropiada una declaración if/else en este caso?

O usa el interruptor y agrega .ToString() al tipo?

Author: Community, 2009-04-02

11 answers

Si realmente tuviera que switch en el tipo de objeto, usaría .ToString(). Sin embargo, lo evitaría a toda costa: IDictionary<Type, int> lo hará mucho mejor, visitante podría ser un exceso, pero por lo demás sigue siendo una solución perfectamente bien.

 66
Author: Anton Gogolev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-02 09:10:32

Esto no resolverá directamente su problema ya que desea cambiar sus propios tipos definidos por el usuario, pero para el beneficio de otros que solo quieren cambiar los tipos integrados, puede usar el código de tipografía enumeración:

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

    case TypeCode.Int32:
        // Handle Int32
        break;
     ...
}
 91
Author: Ashley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-16 10:53:06

En la entrada del blog de MSDN Muchas preguntas: encienda el tipo hay alguna información sobre por qué . NET no proporciona conmutación de tipos.

Como de costumbre - siempre existen soluciones alternativas.

Este no es mío, pero desafortunadamente he perdido la fuente. Hace posible el cambio de tipos, pero personalmente creo que es bastante incómodo (la idea del diccionario es mejor):

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

Uso:

 new Switch(foo)
     .Case<Fizz>
         (action => { doingSomething = FirstMethodCall(); })
     .Case<Buzz>
         (action => { return false; })
 39
Author: Arnis Lapsa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-21 15:47:54

Solo usaría una declaración if. En este caso:

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

La otra forma de hacer esto es:

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

El primer ejemplo es verdadero solo para tipos exactos, donde este último también comprueba la herencia.

 24
Author: David Wengier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-26 19:09:00

Me enfrento al mismo problema y me encontré con este post. ¿Es esto lo que se entiende por el enfoque 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 es así, no puedo decir que soy un fan de conciliar los números en el diccionario con las declaraciones de caso.

Esto sería ideal, pero la referencia del diccionario lo mata:

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

¿Hay otra implementación que he pasado por alto?

 22
Author: bjaxbjax,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-02 20:17:25

Puedes hacer esto:

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

Si bien eso sería más elegante, posiblemente no sea tan eficiente como algunas de las otras respuestas aquí.

 11
Author: Dave Van den Eynde,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-02 09:12:33

Puedes hacer esto:

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 claro y fácil. Es un poco más lento que almacenar en caché el diccionario en algún lugar.. pero para un montón de código esto no importará de todos modos..

 8
Author: nreyntje,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-04 00:52:52

Un enfoque es agregar un método virtual puro GetNodeType() a NodeDTO y sobrescribirlo en los descendientes para que cada descendiente devuelva el tipo real.

 7
Author: sharptooth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-02 09:13:11

Dependiendo de lo que esté haciendo en la instrucción switch, la respuesta correcta es el polimorfismo. Simplemente coloque una función virtual en la clase interfaz/base y anule para cada tipo de nodo.

 4
Author: Jason Coyne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-02 14:08:20

Usaría la cadena (Nombre) en la parte superior del interruptor:

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

                            default:
                                    return -1;
                                    break;
                    }
            }
 0
Author: Program.X,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-02 09:10:57

En realidad prefiero el enfoque dado como la respuesta aquí: ¿Hay una alternativa mejor que esta para 'activar el tipo'?

Sin embargo, hay un buen argumento acerca de no implementar ningún tipo de comparación methids en un lenguaje orientado a objetos como C#. Como alternativa, podría extender y agregar la funcionalidad adicional requerida utilizando la herencia.

Este punto fue discutido en los comentarios del blog de los autores aqui: http://blogs.msdn.com/b/jaredpar/archive/2008/05/16/switching-on-types.aspx#8553535

Me pareció un punto extremadamente interesante que cambió mi enfoque en una situación similar y solo espero que esto ayude a otros.

Saludos cordiales, Wayne

 0
Author: Wayne Phipps,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:39