Pergunta

Duplicate possíveis:
C # - Existe uma melhor alternativa do que isso para 'switch no tipo'?

Se você quiser switch em um tipo de objeto, qual é a melhor maneira de fazer isso?

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

Eu sei que isso não funciona dessa maneira, mas eu queria saber como você poderia resolver isso. É um apropriado declaração if/else neste caso?

Ou você usar a opção e adicionar .ToString() ao tipo?

Foi útil?

Solução

Se eu realmente teve que switch no tipo de objeto, eu usaria .ToString(). No entanto, gostaria de evitar a todo o custo: IDictionary<Type, int> vai fazer muito melhor, visitante pode ser um exagero mas caso contrário, ainda é uma solução perfeitamente bem.

Outras dicas

Isto não vai resolver diretamente o seu problema que você quer mudar em seus próprios tipos definidos pelo usuário, mas para o benefício de outros que só querem ligar tipos built-in, você pode usar o TypeCode enumeração:

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

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

No blog MSDN Muitas perguntas: Interruptor do tipo é algumas informações sobre o porquê .NET não fornece ligar tipos.

Como de costume -. Soluções Alternativas sempre existe

Este não é meu, mas infelizmente eu perdi a fonte. Faz ligar tipos possíveis, mas eu pessoalmente acho que é muito estranho (a idéia dicionário é melhor):

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

Eu tinha acabado de usar uma instrução if. Nesse caso:

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

A outra maneira de fazer isso é:

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

O primeiro exemplo é válido para tipos exatos somente, onde as últimas verificações de herança também.

Eu sou confrontado com o mesmo problema e me deparei com este post. É isso que se quer dizer com a abordagem 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;
    }
}

Se assim for, não posso dizer que eu sou um fã de conciliar os números no dicionário com as declarações de caso.

Este seria o ideal mas a referência dicionário mata-lo:

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 outra aplicação que eu tenha esquecido?

Você pode fazer isso:

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

Enquanto que seria mais elegante, não é possivelmente tão eficiente quanto algumas das outras respostas aqui.

Você pode fazer isso:

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

É claro e é fácil. É um pouco mais lento do que o cache do lugar dicionário .. mas para os lotes de código isso não importa de qualquer maneira ..

Uma abordagem é adicionar um método puro GetNodeType virtual () para NodeDTO e substituí-lo nos descendentes de modo que cada retornos descendentes tipo real.

Dependendo do que você está fazendo na instrução switch, a resposta correta é polimorfismo. Basta colocar uma função virtual na classe de interface / base e de substituição para cada tipo de nó.

Na verdade, eu prefiro a abordagem dada como a resposta aqui: Existe uma alternativa melhor do que isso 'switch no tipo'?

Há, porém, um bom argumento por não implementar qualquer methids de comparação de tipo em uma linguagem orientada a objeto como C #. Você poderia como alternativa estender e adicionar funcionalidades extra necessário usar a herança.

Este ponto foi discutido nos comentários dos autores do blog aqui: http: // blogs. msdn.com/b/jaredpar/archive/2008/05/16/switching-on-types.aspx#8553535

Eu encontrei este um ponto extremamente interessante, que mudou a minha abordagem em uma situação semelhante e só espero que isso ajude os outros.

Atenciosamente, Wayne

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top