Como faço para despachar para um método com base no tipo de tempo de execução de um parâmetro em C# <4?

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

  •  26-09-2019
  •  | 
  •  

Pergunta

Eu tenho um objeto o que garantiu o tempo de execução para ser um dos três tipos A, B, ou C, todos os quais implementam uma interface comum I. Eu posso controlar I, mas não A, B, ou C. (Assim, eu poderia usar uma interface marcador vazia ou, de alguma forma, aproveitar as semelhanças nos tipos usando a interface, mas não posso adicionar novos métodos ou alterar os existentes nos tipos.)

Eu também tenho uma série de métodos MethodA, MethodB, e MethodC. O tipo de tempo de execução de o é procurado e é usado como um parâmetro para esses métodos.

public void MethodA(A a) { ... }
public void MethodB(B b) { ... }
public void MethodC(C c) { ... }

Usando esta estratégia, agora um cheque deve ser realizado no tipo de o para determinar qual método deve ser invocado. Em vez disso, gostaria de simplesmente ter três métodos sobrecarregados:

public void Method(A a) { ... } // these are all overloads of each other
public void Method(B b) { ... }
public void Method(C c) { ... }

Agora estou deixando C# fazer o despacho em vez de fazer isso manualmente. Isso pode ser feito? A abordagem ingênua direta não funciona, é claro:

Não é possível resolver o método 'Método (objeto)'. Os candidatos são:

  • Método void (a)
  • Método Void (B)
  • Método vazio (C)
Foi útil?

Solução

Que tal algo como isso?

private Dictionary<Type, Action<I>> _mapping = new Dictionary<Type, Action<I>>
{ 
  { typeof(A), i => MethodA(i as A)},
  { typeof(B), i => MethodB(i as B)},
  { typeof(C), i => MethodC(i as C)},
};

private void ExecuteBasedOnType(object value)
{
    if(_mapping.ContainsKey(value.GetType()))
       _mapping(value.GetType())(value as I);
}

Outras dicas

Se você pode refatorar isso, mova o método para a interface e tenha cada classe com sua implementação:

I i = o as I;
i.Method();

Se a 3 Classe A, B e C implementarem a interface I, você não deve fazer nada. É o tempo de execução que escolhe o método certo para você:

A a = new A();
class.Method(a); // will calll Method(A a)

B b = new B();
class.Method(b); // will call Method(B b)

Não tenho 100% de certeza se isso funcionará em seu cenário, mas parece que você pode usar classes parciais:

public interface IMethodCallable
{
    public void Method();
}

public partial class A : IMethodCallable
{
    public void Method()
    {
        ....
    }
}

Então, para o uso:

object o = getObject(); // we know this is A, B or C
((IMethodCallable)o).Method();

Pré -tome o O é declarado como tipo/interface i, instanciado como ab ou c. A maneira de fazer isso seria ter um único método público o param do tipo I e depois fazer sua lógica nesse método, por exemplo, Método Privado AB ou C.

Lendo sua postagem editada, O é do tipo de tipo, lembre -se de deixar claro quando você aceita um objeto porque, além de ser o tipo AC#, é um termo OOP genérico para uma instância de uma classe.

Por que você está declarando isso como um objeto, e não como I, pode ser outra coisa mais tarde?

Se for assim, para usar seus métodos sobrecarregados, você precisaria unir -o antes de ligar para o método. por exemplo

if (o.GetType() == typeof(a))
{
   oa = (a)o;
   Method(oa);
}
else if(o.GetType() == typeof(b))
{
    ...
}

Etc.

Como alternativa, se você fez o método pegar um paramater do tipo I, você poderia fazer algo como:

i oi = (i)o;
Method(oi);

Mas você ainda precisaria fazer algo como o primeiro exemplo do seu método público.

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