2011-09-22 6 views
1

J'ai créé ces classes:Comment appeler une méthode virtuelle de classe dérivée?

public abstract class Node 
{ 
    public virtual NodeModel CreateModel() 
    { 
     throw new NotImplementedException(); 
    } 
} 

public class Folder : Node 
{ 
    public virtual FolderModel CreateModel() 
    { 
     // Implementation 
    } 
} 

public class Item : Node 
{ 
    public virtual ItemModel CreateModel() 
    { 
     // Implementation 
    } 
} 

Puis dans mon programme, j'ai une liste de nœud qui ne contient que des objets de l'objet et des dossiers. Lorsque je boucle sur la liste et que j'essaie d'appeler la méthode CreateModel(), c'est toujours la méthode de la classe Node qui est appelée (par conséquent, elle lève l'exception).

Je ne peux pas modifier CreateModel() pour abstrait car le type de retour est différent en fonction du type dérivé. Je me demandais s'il était possible d'avoir un type de retour différent. Je veux aussi éviter les génériques. Le fait est que Intellisense me montre la méthode de classe supérieure en jouant avec une instance de celui-ci. Si je supprime l'implémentation virtuelle de la classe supérieure, elle affiche l'implémentation de la classe de base. C'est là que je pensais que c'est réellement possible. Alors, comment puis-je forcer le programme à appeler la méthode de classe supérieure?


EDIT: La réponse est en fait simple et était juste sous mon nez. Le type de retour n'a pas d'importance car il héritera du type de retour défini dans le résumé de classe de base CreateModel(). Je viens de marquer la méthode comme abstraite dans ma classe de base et ça marche très bien. Je ne sais pas pourquoi j'ai été troublé à certains moments parce que maintenant cela me semble assez évident.

Merci à tous pour m'avoir aidé.

+1

Avec « supérieur », voulez-vous dire la classe de base (ie. Node) ou l'une des sous-classes/classes dérivées (article ou dossier). S'il vous plaît mettre à jour votre question car il est un peu difficile ... –

+0

Merci d'avoir signalé cette erreur. – Ucodia

+0

C# ne peut pas faire de résolution de méthode basée sur le type de retour, donc (sauf si vous utilisez des génériques comme Jon Skeet le suggérait) je devrais vous renvoyer un objet: public virtual object CreateModel() ' –

Répondre

1

C# ne prend pas en charge covariance dans les types de retour de la fonction. De toute façon, il suffit de spécifier le type de retour de CreateModel() comme autre chose que NodeModel lorsque les autres parties se basent sur eux pour être plus spécifiques, par exemple. lorsque FolderModel étend NodeModel avec plus de méthodes.

Si vous ne faites que parcourir une liste d'objets Node et appeler CreateModel(), il n'est pas nécessaire, déclarez simplement Folder.CreateModel() avec le type de retour NodeModel, même s'il renvoie un FolderModel.

+0

Votre réponse a repéré ce qui me manquait. Le type de retour n'a pas d'importance car FolderModel hérite de NodeModel. Je viens de déclarer la fonction comme abstraite sur la classe de base et ça fonctionne comme prévu. Un grand merci à vous et aux autres personnes présentes :) – Ucodia

2

Il me semble que votre classe de base devrait être générique, avec vos classes dérivées spécifiant l'argument de type approprié.

public abstract class Node<T> where T : NodeModel 
{ 
    public abstract T CreateModel(); 
} 

public class Folder : Node<FolderModel> 
{ 
    public override FolderModel CreateModel() 
    { 
     // Implementation 
    } 
} 

public class Item : Node<ItemModel> 
{ 
    public override ItemModel CreateModel() 
    { 
     // Implementation 
    } 
} 

Maintenant vous avez une seule méthode, surchargée de manière appropriée - au lieu de se cacher de la méthode qui allait toujours être embrouillé.

EDIT: Si vous voulez être en mesure de se référer à ces sans génériques, vous pouvez toujours créer une interface non générique, comme ceci:

public interface INode 
{ 
    NodeModel CreateModel(); 
} 

public abstract class Node<T> : INode where T : NodeModel 
{ 
    public abstract T CreateModel(); 

    // Explicit interface implementation so we can implement INode.CreateModel 
    // with a different return type. Just delegate to the strongly-typed method. 
    NodeModel INode.CreateModel() 
    { 
     return CreateModle(); 
    } 
} 
+0

Oui j'aurais dû préciser que je veux éviter les génériques pour une raison quelconque, désolé d'avoir oublié ce détail. Je les utilise la plupart du temps mais dans ce cas particulier, mes classes auront probablement beaucoup de dérivation à bien des égards et cela ajoutera trop de complexité. Mais encore, s'il n'y a pas d'autre moyen, je reviendrai probablement sur cette idée. Merci. – Ucodia

+0

@Ucodia: Je suspecte fortement que vous constaterez que cela ajoutera * moins * de complexité que d'utiliser la méthode de masquage. Je ferai un montage avec une autre suggestion ... –

+0

Oui, je sais que c'est la bonne façon, mais l'implémentation de mon Node ici n'est pas complète et c'est là que les problèmes se poseront. Maintenant, il semble que je vais devoir utiliser des génériques mais j'attendrai d'autres réactions. – Ucodia

0

Voici une version où l'héritage de classe est utilisé à la place des médicaments génériques:

public abstract class Node 
{ 
    public virtual NodeModel CreateModel() 
    { 
     throw new NotImplementedException(); 
    } 
} 

public class FolderModel : NodeModel 
{ 
    // blah 
} 

public class Folder : Node 
{ 
    public virtual NodeModel CreateModel() 
    { 
     var node = new FolderModel(); 
     blah; 
     return node; // FolderModel derives from NodeModel 
    } 
} 

public class ItemModel : NodeModel 
{ 
    // blah 
} 

public class Item : Node 
{ 
    public virtual NodeModel CreateModel() 
    { 
     var node = new ItemModel(); 
     blah; 
     return node; // ItemModel derives from NodeModel 
    } 
} 

public foo(Node node) 
{ 
    var model = node.CreateModel(); 
} 

Le type de model dépend du type de noeud. La manipulation des parties spécifiques du modèle doit en quelque sorte faire partie des méthodes de noeud virtuel qui connaissent les inners de chaque modèle spécifique.

0
public abstract class Node 
{ 
    public virtual NodeModel CreateModel() 
    { 
     throw new NotImplementedException(); 
    } 
} 

public class Folder : Node 
{ 
    public virtual FolderModel CreateModel() 
    { 
     // Implementation 
    } 
} 

Il ne s'agit pas d'un dépassement de méthode mais d'une surcharge.

Node node=new Folder(); 
node.CreateModel();//Of Folder 

Pour ce faire, vous devez remplacer CreateModel dans dérivés (dossier) Classe

Questions connexes