web-dev-qa-db-fra.com

Recherche du type concret derrière une instance d'interface

Pour faire court, j'ai une fonction C # qui exécute une tâche sur un type donné qui est passée en tant qu'instance d'objet. Tout fonctionne bien 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.

Voici le mauvais exemple omniprésent (resplendissant avec une casse de 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
}

J'aimerais que le code de PerformAction utilise Reflection contre son paramètre et voit 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 (), j'obtiens le type d'IA - pas ce que je veux.

Comment PerformAction peut-il déterminer le type concret sous-jacent de l'instance d'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 comme une instance d'interface.

43
Rowan
Type objectType = myObject.GetType();

Devrait toujours vous donner le type de béton, selon votre exemple.

75
Stan R.

Qu'est-ce que vous faites, c'est vraiment la conception du lit, mais vous n'avez pas besoin d'utiliser la réflexion, vous pouvez le vérifier comme ceci

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
}
5
Arsen Mkrtchyan

Je dois être d'accord sur le mauvais design. Si vous avez une interface, cela devrait être parce que vous devez utiliser certaines fonctionnalités communes sans vous soucier de la mise en œuvre concrète. Étant donné votre exemple, il semble que la méthode PerformAction devrait en fait 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);
5
jrista

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

3
Chris Johnston

Peut-être que vous recherchez est l'opérateur

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
}
1
kova