2009-07-21 16 views
36

Pour raccourcir une histoire courte, j'ai une fonction C# qui effectue une tâche sur un type donné qui est transmis en tant qu'instance Object. Tout fonctionne correctement lorsqu'une instance de classe est transmise. Cependant, lorsque l'objet est déclaré en tant qu'interface, j'aimerais vraiment trouver la classe concrète et effectuer l'action sur ce type de classe.Recherche du type concret derrière une instance d'interface

Voici le mauvais exemple omniprésent (resplendissante avec boîtier propriété incorrecte, 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 
} 

Je voudrais le code PerformAction à utiliser la réflexion contre c'est paramètre et voir que ce n'est pas seulement une instance de IA mais que c'est une instance de B et de voir la propriété "b" via GetProperties(). Si j'utilise .GetType(), je reçois le type de IA - pas ce que je veux.

Comment PerformAction peut-il déterminer le type concret sous-jacent de l'instance de IA?

Certains pourraient être tentés de suggérer d'utiliser une classe abstraite mais ce n'est que la limitation de mon mauvais exemple. La variable sera déclarée à l'origine en tant qu'instance d'interface.

+7

Cela ressemble à un mauvais design. Vous devriez utiliser le polymorphisme au lieu de connaître votre méthode sur des types concrets particuliers. Que se passe-t-il si vous en ajoutez un plus tard? –

+4

Cela ne va-t-il pas à l'encontre du but d'une interface? Vous ne devriez pas se soucier de ce que le type concret est tant qu'il implémente l'interface. –

+2

+1 à John et Chris, ce n'est pas seulement mauvais design, mais la question n'a aucun sens. –

Répondre

56
Type objectType = myObject.GetType(); 

devrait vous donner encore le type de béton, selon votre exemple.

+2

Oui, l'appel "myObject.GetType()" NE retournera JAMAIS le type d'interface. – TcKs

+0

Le paramètre de 'PerfomAction' est' object', mais il ne pouvait pas faire: 'IA.getType()' par exemple. –

2

Vous ne pouvez jamais avoir d'instances d'une interface. Il n'est donc pas possible de déterminer s'il s'agit d'une interface ou d'un type concret, car il s'agit toujours d'un type concret. Je ne suis donc pas sûr que votre question ait un sens. Qu'est-ce que vous essayez exactement de faire et pourquoi?

+2

+1 exactement, en fait son exemple fonctionne bien. –

5

Qu'est-ce que vous faites est vraiment la conception lit, mais vous ne devez pas utiliser la réflexion, vous pouvez le vérifier comme celui-ci

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

Ceci est encore un mauvais design, car vous dépendez toujours du type de béton. Cela va largement à l'encontre du but d'avoir une interface en premier lieu ... – jrista

+0

Je crie dans ma tête: "LSP, ISP, DIP !!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!! " – Sebastien

0

Peut-être que vous cherchez le 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

vous le lancez deux fois. Utilisez immédiatement l'opérateur 'as' et vérifiez null plus tard – nawfal

4

Je suis d'accord au sujet de la mauvaise conception. Si vous avez une interface, cela devrait être dû au fait que vous devez utiliser certaines fonctionnalités communes sans vous préoccuper de l'implémentation concrète. Étant donné que vous êtes un exemple, il semble que la méthode PerformAction devrait faire partie de l'interface:

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