2009-07-21 11 views
36

Para abreviar, tengo una función C# que realiza una tarea en un tipo dado que se pasa como una instancia de objeto. Todo funciona bien cuando se pasa una instancia de clase. Sin embargo, cuando el objeto se declara como una interfaz, realmente me gustaría encontrar la clase concreta y realizar la acción sobre ese tipo de clase.Encontrar el tipo concreto detrás de una instancia de interfaz

Aquí es el mal ejemplo ubicua (resplandeciente de propiedad incorrecta carcasa etc):

public interface IA 
{ 
    int a { get; set; } 
} 
public class B : IA 
{ 
    public int a { get; set; } 
    public int b { get; set; } 
} 
public class C : IA 
{ 
    public int a { get; set; } 
    public int c { get; set; } 
} 

// snip 

IA myBObject = new B(); 
PerformAction(myBObject); 

IA myCObject = new C(); 
PerformAction(myCObject); 

// snip 

void PerformAction(object myObject) 
{ 
    Type objectType = myObject.GetType(); // Here is where I get typeof(IA) 
    if (objectType.IsInterface) 
    { 
     // I want to determine the actual Concrete Type, i.e. either B or C 
     // objectType = DetermineConcreteType(objectType); 
    } 
    // snip - other actions on objectType 
} 

Me gustaría que el código en PerformAction utilizar la reflexión contra el que es el parámetro, y ve que no es sólo una instancia de IA pero que es una instancia de B y para ver la propiedad "b" a través de GetProperties(). Si uso .GetType() obtengo el tipo de IA, no lo que quiero.

¿Cómo puede PerformAction determinar el tipo concreto subyacente de la instancia de IA?

Algunos podrían tener la tentación de sugerir el uso de una clase abstracta, pero esa es solo la limitación de mi mal ejemplo. La variable se declarará originalmente como una instancia de interfaz.

+7

Esto suena como un mal diseño. Debe usar el polimorfismo en lugar de que su método conozca los tipos concretos concretos. ¿Qué pasa si agregas uno más tarde? –

+4

¿No derrota eso el propósito de una interfaz? No debe importar cuál es el tipo de hormigón siempre que implemente la interfaz. –

+2

+1 a John y Chris, no solo es un mal diseño, sino que la pregunta no tiene ningún sentido. –

Respuesta

56
Type objectType = myObject.GetType(); 

aún debe darle el tipo de hormigón, de acuerdo con el ejemplo.

+2

Sí, la llamada "myObject.GetType()" wil NEVER devuelve el tipo de interfaz. – TcKs

+0

El parámetro de 'PerfomAction' es' object', pero no pudo: 'IA.getType()' por ejemplo. –

2

Nunca puede tener instancias de una interfaz. Por lo tanto, no es posible determinar si se trata de una interfaz o un tipo concreto, ya que siempre se tratará de un tipo concreto. Entonces no estoy seguro de que tu pregunta tenga algún sentido. ¿Qué estás tratando de hacer exactamente y por qué?

+2

+1 exactamente, de hecho su ejemplo funciona bien. –

5

¿Qué haces es realmente diseño de la cama, pero que no tiene que utilizar la reflexión se puede comprobar como esta

void PerformAction(object myObject) 
{ 
    B objectType = myObject as B; // Here is where I get typeof(IA) 
    if (objectType != null) 
    { 
     //use objectType.b 
    } 
    else 
    { 
     //Same with A 
    } 
    // snip - other actions on objectType 
} 
+2

Este sigue siendo un diseño bastante malo, ya que todavía depende del tipo de hormigón. Esto en gran medida frustra el propósito de tener una interfaz en primer lugar ... – jrista

+0

Estoy gritando en mi cabeza: "LSP, ISP, DIP !!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!! " – Sebastien

0

Quizás esté interesado para la is operator

void PerformAction(object myObject) 
{ 
    if (myObject is B) 
    { 
     B myBObject = myObject as B; 
     myBObject.b = 1; 
    } 

    if (myObject is C) 
    { 
     C myCObject = myObject as C; 
     myCObject.c = 1; 
    } 

    // snip - other actions on objectType 
} 
+0

lo estás lanzando dos veces. Utilice el operador 'as' inmediatamente y busque nulo después – nawfal

4

tengo que estar de acuerdo sobre el mal diseño. Si tiene una interfaz, debe ser porque necesita utilizar algunas funcionalidades comunes sin preocuparse por la implementación concreta. Dado su ejemplo, parece que el método PerformAction debería ser parte de la interfaz:

public interface IA 
{ 
    int a { get; set; } 
    void PerformAction(); 
} 

public class B: IA 
{ 
    public int a { get; set; } 
    public int b { get; set; } 

    public void PerformAction() 
    { 
     // perform action specific to B 
    } 
} 

public class C : IA 
{ 
    public int a { get; set; } 
    public int c { get; set; } 

    public void PerformAction() 
    { 
     // perform action specific to C 
    } 
} 

void PerformActionOn(IA instance) 
{ 
    if (instance == null) throw new ArgumentNullException("instance"); 

    instance.PerformAction(); 

    // Do some other common work... 
} 


B b = new B(); 
C c = new C(); 

PerformActionOn(b); 
PerformActionOn(c); 
Cuestiones relacionadas