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?
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)
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.