2010-05-12 13 views
5

Tengo un objeto o que garantizado en tiempo de ejecución para ser uno de tres tipos A, B, o C, todos los cuales implementan una interfaz común I. Puedo controlar I, pero no A, B, o C. (Por lo tanto, podría usar una interfaz de marcador vacía, o de alguna manera aprovechar las similitudes en los tipos mediante el uso de la interfaz, pero no puedo agregar nuevos métodos o cambiar los existentes).¿Cómo envío a un método basado en el tipo de tiempo de ejecución de un parámetro en C# <4?

También tengo un serie de métodos MethodA, MethodB y MethodC. Se busca el tipo de tiempo de ejecución o y luego se usa como parámetro para estos métodos.

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

Utilizando esta estrategia, en este momento un cheque tiene que ser realizada en el tipo de o para determinar qué método debe ser invocado. En su lugar, me gustaría simplemente tienen tres métodos sobrecargados:

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

Ahora estoy dejando C# hacer el envío en lugar de hacerlo de forma manual a mí mismo. Se puede hacer esto? El enfoque simple ingenuo no funciona, por supuesto:

No se puede resolver el método 'Método (objeto)'. Los candidatos son:

  • Método void (A)
  • Método void (B)
  • void Método (C)
+0

pruébalo? la-la-la –

+0

Si hubiera tipos D, E y F, ¿necesitarían todos una implementación del método también? –

+0

@Jason: Presumiblemente, sí, pero en mi caso particular es poco probable que existan otros tipos de este tipo. –

Respuesta

5

¿Qué tal algo así?

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

¡Ja, esto es lo que tengo actualmente! Obviamente, no es tan bueno como dejar que C# haga el despacho de alguna manera. –

+0

Si tiene control sobre I, A, B y C, podría agregar algo a lo que llamé ExecuteMethod() y simplemente llamarlo a I. Si no, debe mapearlo de alguna manera. –

+0

Esta es su mejor opción si no puede aplicar la sugerencia de Kobi. No se puede hacer un doble patrón de despacho/visitante a menos que usted también controle las clases. –

0

Si el 3 de clase A, B y C implementa la interfaz Yo no deberías hacer nada. Es el tiempo de ejecución que elegir el método adecuado para usted:

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

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

Esto no responde la pregunta correctamente (o al menos no entiende lo que estaba diciendo). No tengo 'A' o' B'; Tengo un 'objeto' (ver la primera oración). –

0

Preseumably O se declara como tipo/interfaz entonces crea una instancia ya sea como un bo c. La forma de hacerlo sería tener un único método público: tomar un parámetro de tipo I y luego hacer tu lógica dentro de ese método, p. llame al método privado AB o C.

Leyendo su publicación editada, o es de tipo objeto, recuerde que debe tenerlo claro cuando se ocupa de un objeto, además de ser aC# tipo, es un término genérico para una instancia de una clase.

¿Por qué lo declaras como un objeto, en lugar de una i, podría ser algo más tarde?

Si es así para usar sus métodos sobrecargados, deberá destrabarlos antes de llamar al método. p.ej.

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

Etc.

Alternativamente, si usted hizo el método toma un parámetro de tipo i de que podía hacer algo como:

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

Pero todavía tendría que hacer algo como la primera ejemplo dentro de su método público.

7

Si puede refactorizar esto, mover el método a la interfaz y hacer que cada clase tiene su aplicación:

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

+1 Exactamente lo que iba a decir. –

+0

He editado para aclarar que controlo 'I', pero no' A', 'B' o' C'. ¡Pero sería genial si pudiera! –

+0

@Evan, use clases parciales (ver mi respuesta) – tster

0

No estoy 100% seguro de si esto va a funcionar en su escenario, pero suena como que podría ser capaz de utilizar las clases parciales:

public interface IMethodCallable 
{ 
    public void Method(); 
} 

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

entonces para el uso:

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