2009-04-16 6 views
3

J'utilise une bibliothèque qui génère un tas de classes pour moi.Comment appeler une méthode de sous-classe sur un objet baseclass?

Ces classes héritent toutes d'une classe de base commune, mais cette classe de base ne définit pas de méthodes communes à toutes les sous-classes.

Par exemple:

SubClassA : BaseClass{ 
    void Add(ItemA item) {...} 
    ItemA CreateNewItem() {...} 
} 

SubClassB: BaseClass{ 
    void Add(ItemB item) {...} 
    ItemB CreateNewItem() {...} 
} 

Malheureusement, la classe de base n'a pas ces méthodes. Ce serait formidable:

BaseClass{ 
    // these aren't actually here, I'm just showing what's missing: 
    abstract void Add(ItemBaseClass item); // not present! 
    abstract ItemBaseClass CreateNewItem(); // not present! 
} 

Comme il existe une classe de base commune pour mes objets A + B et une classe de base commune pour les objets Item, je l'avais espéré profiter du merveilleux monde du polymorphisme.

Malheureusement, comme les méthodes communes ne sont pas réellement présentes dans la classe de base, je ne peux pas les appeler virtuellement. par exemple, ce serait parfait:

BaseClass Obj; 
Obj = GetWorkUnit(); // could be SubClassA or SubClassB 

ItemBaseClass Item = Obj.CreateNewItem(); // Compile Fail: CreateNewItem() isn't in the base class 

Item.DoSomething(); 

Obj.Add(Item); // Compile Fail: Add(...) isn't in the base class 

coulée De toute évidence fonctionnerait, mais je aurais besoin de savoir quel type j'avais qui annulerait les avantages. Comment puis-je "forcer" un appel à ces méthodes? Je ne m'inquiète pas d'obtenir un objet qui n'applique pas la méthode que j'essaie d'appeler. Je peux réellement faire ce que je veux en VB - je ne suis pas IntelliSense, mais est content et il fonctionne le compilateur:

CType(Obj, Object).Add(Item) // Note: I'm using C#--NOT VB 

againt, je n'ai pas le contrôle de ces classes (que je pense que les règles sur les classes partielles) .

+0

Quel est le problème avec votre propre méthode alors? N'utilisez le mien que si vous avez l'option Strict On –

+0

Avez-vous le contrôle de la sous-classe? Si vous le faites, allez avec la solution de Lucero. –

+1

@Michael Haren: C# n'a pas d'option Strict du tout. Ma solution fonctionne si vous n'avez aucun contrôle sur les classes, la solution de Lucero est la meilleure si vous avez le contrôle sur les sous-classes. –

Répondre

6

Vous ne pouvez pas appeler une méthode non virtuelle d'une classe dérivée sans recourir à la réflexion ou à d'autres astuces sales. Si vous voulez le faire, il est facile alors:

// obj is your object reference. 
obj.GetType().InvokeMember("MethodName", 
    System.Reflection.BindingFlags.InvokeMethod, null, obj, null /* args */) 
+1

Je suis prêt à utiliser des astuces sales! Ça ne peut pas être * ça * fou si VB l'accepte joyeusement ... bon ok, ça peut l'être, mais j'aimerais bien voir ... –

+0

Pourquoi la réflexion est-elle un sale tour? :) Il est assez commun de nos jours et vous pouvez même le faire égaler le code sans réflexion – majkinetor

+1

Il est considéré comme un mauvais tour quand vous devez utiliser le polymorphisme. –

0
+0

Déclarez ce que virtuel? Les méthodes ne sont pas présentes dans les classes de base. –

+0

Les méthodes de classe de base doivent être virtuelles, avec le mot-clé "override" dans les implémentations de sous-classe. Voir ma réponse ci-dessous. –

+0

@Kevin: les méthodes ne sont pas dans la classe de base. J'ai commenté plus loin votre réponse. –

3

je pourrais manquer quelque chose, mais pourquoi ne pas faire et d'hériter d'une interface avec ces méthodes ? Si vous contrôlez le processus de création des instances, vous pouvez obtenir ce que vous voulez en héritant des classes que vous n'avez pas écrites et en ajoutant ensuite interface (aucun code à écrire, le compilateur mappe l'interface avec les méthodes non virtuelles existantes).

+0

Il n'a aucun contrôle sur les classes. –

+0

Peut-être que je dois être plus précis alors ...;) – Lucero

+0

Droit. C'est ce que j'ai commencé avec mais sans contrôle sur les classes, je ne peux pas le faire. –

0

Si vous utilisez Visual Studio 2008, vous pouvez créer une méthode d'extension pour la classe de base. À l'intérieur de cette méthode d'extension, vous feriez le cast et appelez la méthode de la sous-classe. Cela devrait fonctionner pour 2.0 cadre des projets ciblés et, aussi longtemps que vous compilez à partir withing VS 2008. Emprunter l'autre code de réflexion proposé, vous pouvez effectuer les opérations suivantes ...

public static class MyExtensions 
{ 
    public static ItemBaseClass CreateNewItem(this BaseClass item) 
    { 
     return item.GetType().InvokeMember("MethodName", System.Reflection.BindingFlags.InvokeMethod, null, obj, null /* args */); 
    } 
} 
+0

Pouvez-vous nous montrer des exemples de code? Je doute qu'il soit possible de le faire proprement. –

+0

C'est une bonne idée mais le but est d'éliminer les gros blocs de commutation comme celui-ci. Merci quand même. –

+0

si vous ne voulez pas les blocs de commutation - aller avec la route de réflexion. Si la performance est une préoccupation, le bloc de commutation pourrait être un meilleur itinéraire. Avoir la méthode d'extension vous permet d'isoler ce commutateur bock dans une méthode facilement appelable. –

0

Une autre possibilité est d'utiliser un mécanisme de proxy, comme un RealProxy (pas très efficace en termes de performance) ou mieux en utilisant dynamiquement DynamicMethods créé de sorte que le surcoût d'utiliser la réflexion est seulement là une fois par type à soutenir, tout en le gardant aussi flexible que la méthode de réflexion . C'est payant lorsque vous devez appeler la méthode plusieurs fois, mais cela nécessite des connaissances de MSIL.

-1

Vous avez oublié le mot clé "override" dans les définitions de méthodes de vos sous-classes. Quand quelque chose est déclaré "abstrait", il est par définition virtuel, et donc dans la sous-classe, vous devez mettre le mot-clé "override" devant la déclaration de la méthode. Donc, ce qui devrait fonctionner est ci-dessous:

BaseClass{ 
    abstract void Add(ItemBaseClass item); // not present! 
    abstract ItemBaseClass CreateNewItem(); // not present! 
} 

SubClassA : BaseClass{ 
    override void Add(ItemA item) {...} 
    override ItemA CreateNewItem() {...} 
} 

SubClassB: BaseClass{ 
    override void Add(ItemB item) {...} 
    override ItemB CreateNewItem() {...} 
} 

Cela devrait fonctionner exactement comme vous le souhaitez dans votre exemple d'utilisation.

+0

@Kevin, merci pour l'aide, mais ce que je voulais montrer, c'est que je ne peux pas toucher ce code - je ne le contrôle pas. les // lignes non présentes ne sont PAS dans le fichier de code - si elles étaient là, je serais en or. –

+0

Ah, je vois. Donc, fondamentalement, vous cherchez un comportement similaire à celui d'une interface sur des choses qui ne déclarent pas une interface commune. Un peu mauvaise conception si les choses avec des méthodes communes n'implémentent pas une interface. Dommage. –

0

Problème n ° 1: vos sous-classes ne prévalent pas quoi que ce soit Problème # 2: vos sous-classes ont des signatures de fonction que votre classe de base

Assurez-vous que vos signatures sont correctes, et si vous les remplaçant, marque les virtuelles et non abstraites. Vous devrez ajouter un corps vide aux fonctions virtuelles de la classe de base si vous ne voulez pas qu'elles fassent quoi que ce soit.

class ItemBase{} 

class ItemA : ItemBase{} 

class ItemB : ItemBase{} 

class BaseClass 
{ 
    public virtual void Add(ItemBase item){} 
    public virtual ItemBase CreateItem() { return null; } 
} 

class ClassA : BaseClass 
{ 
    public override void Add(ItemBase item) 
    { 
     //do whatever 
     throw new NotImplementedException(); 
    } 

    public ItemBase CreateItem() 
    { 
     //create an ItemBase and return 
     throw new NotImplementedException(); 
    } 
} 
+0

MStodd, merci pour la suggestion mais malheureusement je n'ai aucun contrôle sur les cours. De plus, ces appels de méthodes ne sont pas réellement présents dans la classe de base, abstraite ou concrète. –

Questions connexes