Compte tenu des classes suivantes: est un moyen d'obtenir Je préfère ne pas copier la méthode de la classe et modifier le type là-bas. p> J'ai besoin d'obtenir un objet J'ai besoin d'obtenir un < Code> Classc Code> Objet lorsque j'appelle Quelque chose comme appeler un constructeur basé sur: classb code> et classc code> pour hériter de la méthode mais personnaliser le retour Tapez à leur propre classe? p> classb code> lorsque j'appelle classb.dosomobliandreturnnewObject () code>. p> classc.dosomethingandreturnNewObject () code>. p> this.getType () code>? Mais je n'ai aucune idée de la façon de faire ça. P> p>
10 Réponses :
Non, la fonctionnalité que vous avez mentionnée est appelée Type de retour Covariant Strong> . Ce n'est pas pris en charge en C #. P>
Bien que je pense que ce sera dans c # 4.0 non?
JK: Non. Je ne pense pas que c # va soutenir cette fonctionnalité. C # 4.0 prend en charge CO-CO-/ Contra-variance pour les génériques i>.
Googling Ce terme donne également cette suggestion sur Microsoft Connect: Connect.Microsoft.com / VisualStudio / Feedback / ...
Correct. Nous ajoutons une variance générique et non de la covariance de type retour.
Ce que vous décrivez est un Type de retour Covariant et n'est pas pris en charge en C #.
Cependant, vous pouvez créer de la classe de classifie comme générique ouverte et que les héritiers génériques fermés renvoient leur propre type. P>
Exemple: P>
public abstract class ClassA<T> where T: ClassA<T>, new()
{
public abstract T DoSomethingAndReturnNewObject();
}
public class ClassB: ClassA<ClassB>
{
public override ClassB DoSomethingAndReturnNewObject()
{
//do whatever
}
}
"Classb et Classc ne peuvent pas hériter de Classa et redéfinir le type de retour tout en soutenant le polymorphisme" - je ne suis pas sûr de ce que vous entendez par cela; Si c'est une déclaration générique, alors c'est faux. Ce qu'il demande est un type de retour covariant. Ceci est pris en charge par C ++ et Java, et assez évidemment ne "casser le polymorphisme" - c'est parfaitement typique, si c'est ce qui est implicite. C'est juste une limitation de CLR.
Vous auriez vraiment besoin de Nouveau code> dans la contrainte générique et que la classe devrait supporter un constructeur par défaut. Je suppose que cela du nom DosomoTrureTrurn__NewObject __ ()
@Anthony oh bon attrape, je ne faisais pas vraiment attention au nom de la méthode. Je pensais que l'OP modifierait l'instance actuelle et je viens de rentrer cela;
@Pavel Cela fonctionne aussi longtemps qu'il suit le principe de substitution de Liskov, c'est vrai. Je modifierai ma réponse pour réfléchir.
Je pense que vous devez créer une nouvelle fonction avec le nouveau type de retour et appelez à l'intérieur de l'autre fonction et manipuler le type renvoyé. Sinon, il ne sera pas logique! (avec la définition / idée d'héritage) p>
Peut-être que les génériques seront votre Sauveur. Jetez un coup d'œil à ce lien:
C # Generics Partie 3/4: Coulée, héritage et méthodes génériques A > bstract class B<T> {
public abstract T Fct(T t);
}
class D1 : B<string>{
public override string Fct( string t ) { return "hello"; }
}
class D2<T> : B<T>{
public override T Fct(T t) { return default (T); }
}
Eh bien, la bonne réponse est non et, généralement, c'est une mauvaise idée. Si vous retournez quelque chose de complètement différent, trouvez une autre manière. P>
Cependant, si vous ne retournez pas quelque chose de complètement différent, une interface peut résoudre votre problème. Au lieu de renvoyer une classe, renvoyez une interface et disposez de classes A, B et C des objets de retour sur qui implémentent cette interface dans la manière dont ils voient en forme. P>
Le type de retour n'est pas "quelque chose de complètement différent". Il y a une relation "is-a" entre Classb et Classa. Déclarer un type de retour plus spécifique de la valeur de retour initiale ne violera pas le principe de substitution de Liskov; En fait, Java lui permet depuis Java 1.5. Pour les arguments d'entrée L'inverse est vrai: déclarer plus d'arguments d'entrée génériques devraient être autorisés dans des classes dérivées.
Oui, mais la question ultime est la raison pour laquelle il faut s'en soucier de la classe B ou de la classe C? Si vous avez besoin de quelque chose de spécifique, son point est correct.
woenen, je ne suis pas sûr de comprendre votre problème. La réponse courante actuelle est une solution fine. Si vous dites que la sous-classe devrait avoir une valeur de retour plus spécifique (qui n'est pas prise en charge, je ne sais donc pas pourquoi nous en discutons), alors je suis en désaccord. C'est une mauvaise forme.
Ce n'est pas l'héritage, car le type de retour de la méthode fait partie de sa signature. Vous ne changez pas la méthode, vous créeriez un tout entier neuf. P>
Vous avez des options. Vous pouvez, par exemple, faire la méthode L'autre alternative consiste à laisser les signatures de méthode as-sont, et ont les méthodes de sous-classe les instances de renvoi de Y a-t-il une raison quelconque l'interface commune de DosomoTreuturnNewObject code> une méthode basée sur générique et renvoie son type générique. C'est probablement le chemin le plus direct vers le comportement exact pour lequel vous cherchez. P>
classb code> et classc code>. Ensuite, le code du client devra être responsable du casting afin d'utiliser ces objets comme leurs classes dérivées appropriées. P>
classa code> ne suffit-il pas? Le polymorphisme sera, si vous avez des membres virtuels dérivés et transférés correctement, vous fournissez la fonctionnalité correcte si vous utilisez uniquement les membres CLASSA code>. P>
Vous devez créer une méthode virtuelle protégée pour le notez le type de retour reste classa mais le type d'instance d'objet sera spécifique. classe. p> p> dosomethandrurturnnewObject code> à utiliser:
Bonne pensée, j'aime celui-ci.
ClassB b1 = new ClassB(); ClassB b2 = b1.DoSomethingAndReturnNewObject(); // returns instance of ClassB
J'ai finalement conçu la solution suivante. Pour mon cas, il est assez utile, mais cela suppose que CLASSA connaît ses dérivés et se limite à ces deux options. Pas vraiment une pensée de haut niveau, mais ça marche. :)
Il y a une réponse vraiment simple: faites toutes les types de renvoi de méthode "objet". Vous retournez évidemment des types différents, des chaînes et des véhiculest et de tels autres, et ils resteront ce qu'ils sont après avoir atteint leur destination. Mais le compilateur est parfaitement heureux - tout est un "objet". Vous donnez une vérification de type temporaire de compilation, ce n'est pas une bonne chose, mais de temps en temps pour une programmation de OO profonde, le retour en vaut la peine. p>