Étant donné que l'héritage multiple est mauvais (cela rend la source plus compliquée), C # ne fournit pas directement un tel modèle. Mais parfois, il serait utile d'avoir cette capacité.
Par exemple, je suis capable d'implémenter le modèle d'héritage multiple manquant en utilisant des interfaces et trois classes comme ça:
public interface IFirst { void FirstMethod(); }
public interface ISecond { void SecondMethod(); }
public class First:IFirst
{
public void FirstMethod() { Console.WriteLine("First"); }
}
public class Second:ISecond
{
public void SecondMethod() { Console.WriteLine("Second"); }
}
public class FirstAndSecond: IFirst, ISecond
{
First first = new First();
Second second = new Second();
public void FirstMethod() { first.FirstMethod(); }
public void SecondMethod() { second.SecondMethod(); }
}
Chaque fois que j'ajoute une méthode à l'une des interfaces, je dois également changer la classe FirstAndSecond .
Existe-t-il un moyen d'injecter plusieurs classes existantes dans une nouvelle classe comme c'est possible en C ++?
Peut-être existe-t-il une solution utilisant une sorte de génération de code?
Ou cela peut ressembler à ceci (syntaxe c # imaginaire):
public class FirstAndSecond: IFirst from First, ISecond from Second
{ }
Pour qu'il n'y ait pas besoin de mettre à jour la classe FirstAndSecond lorsque je modifie l'une des interfaces.
ÉDITER
Il serait peut-être préférable de considérer un exemple pratique:
Vous avez une classe existante (par exemple, un client TCP basé sur du texte basé sur ITextTcpClient) que vous utilisez déjà à différents endroits dans votre projet. Vous ressentez maintenant le besoin de créer un composant de votre classe pour être facilement accessible aux développeurs de formulaires Windows.
Autant que je sache, vous avez actuellement deux façons de procéder:
Écrivez une nouvelle classe héritée des composants et implémente l'interface de la classe TextTcpClient à l'aide d'une instance de la classe elle-même, comme illustré avec FirstAndSecond.
Écrivez une nouvelle classe qui hérite de TextTcpClient et implémente en quelque sorte IComponent (ne l'ont pas encore essayé).
Dans les deux cas, vous devez travailler par méthode et non par classe. Puisque vous savez que nous aurons besoin de toutes les méthodes de TextTcpClient et Component, ce serait la solution la plus simple pour simplement combiner ces deux en une seule classe.
Pour éviter les conflits, cela peut être fait par génération de code où le résultat pourrait être modifié par la suite, mais le taper à la main est une pure douleur dans le cul.
la source
Réponses:
C # et le .net CLR n'ont pas implémenté MI car ils n'ont pas encore conclu comment il interagirait entre C #, VB.net et les autres langages, pas parce que "cela rendrait la source plus complexe"
L'IM est un concept utile, les questions sans réponse sont celles comme: - "Que faites-vous lorsque vous avez plusieurs classes de base communes dans les différentes superclasses?
Perl est la seule langue avec laquelle j'ai jamais travaillé où MI fonctionne et fonctionne bien. .Net pourrait bien l'introduire un jour mais pas encore, le CLR supporte déjà MI mais comme je l'ai dit, il n'y a pas encore de construction de langage pour cela.
Jusque-là, vous êtes coincé avec des objets proxy et plusieurs interfaces à la place :(
la source
Envisagez simplement d'utiliser la composition au lieu d'essayer de simuler l'héritage multiple. Vous pouvez utiliser des interfaces pour définir quelles classes composent la composition, par exemple:
ISteerable
implique une propriété de typeSteeringWheel
,IBrakable
implique une propriété de typeBrakePedal
, etc.Une fois que vous avez fait cela, vous pouvez utiliser la fonctionnalité Méthodes d'extension ajoutée à C # 3.0 pour simplifier davantage les méthodes d'appel sur ces propriétés implicites, par exemple:
la source
myCar
a fini de tourner à gauche avant d'appelerStop
. Il peut se renverser s'il estStop
appliquémyCar
à une vitesse excessive. : DJ'ai créé un post-compilateur C # qui permet ce genre de chose:
Vous pouvez exécuter le post-compilateur en tant qu'événement post-build de Visual Studio:
Dans le même assemblage, vous l'utilisez comme ceci:
Dans un autre assemblage, vous l'utilisez comme ceci:
la source
Vous pouvez avoir une classe de base abstraite qui implémente à la fois IFirst et ISecond, puis hériter uniquement de cette base.
la source
L'IM n'est PAS mauvais, tout le monde qui l'a (sérieusement) utilisé l'aime et cela ne complique PAS le code! Au moins pas plus que d'autres constructions peuvent compliquer le code. Un mauvais code est un mauvais code, que MI soit ou non dans l'image.
Quoi qu'il en soit, j'ai une jolie petite solution pour l'héritage multiple que je voulais partager, c'est à; http://ra-ajax.org/lsp-liskov-substitution-principle-to-be-or-not-to-be.blog ou vous pouvez suivre le lien dans mon sig ... :)
la source
myFoo
est de typeFoo
, qui hérite deMoo
etGoo
, qui héritent deBoo
, alors(Boo)(Moo)myFoo
et(Boo)(Goo)myFoo
ne seraient pas équivalents). Connaissez-vous des approches préservant l'identité?Dans ma propre implémentation, j'ai trouvé que l'utilisation de classes / interfaces pour MI, bien que "bonne forme", avait tendance à être une complication excessive, car vous devez configurer tout cet héritage multiple pour seulement quelques appels de fonction nécessaires, et dans mon cas, devait être fait littéralement des dizaines de fois de manière redondante.
Au lieu de cela, il était plus facile de simplement créer des "fonctions qui appellent des fonctions qui appellent des fonctions" statiques dans différentes variétés modulaires comme une sorte de remplacement de POO. La solution sur laquelle je travaillais était le "système de sorts" pour un RPG où les effets doivent fortement mélanger et assortir la fonction d'appel pour donner une variété extrême de sorts sans réécrire le code, un peu comme l'exemple semble l'indiquer.
La plupart des fonctions peuvent désormais être statiques car je n'ai pas nécessairement besoin d'une instance pour la logique des sorts, alors que l'héritage de classe ne peut même pas utiliser de mots clés virtuels ou abstraits en statique. Les interfaces ne peuvent pas du tout les utiliser.
Le codage semble beaucoup plus rapide et plus propre de cette façon OMI. Si vous ne faites que des fonctions et n'avez pas besoin de propriétés héritées , utilisez des fonctions.
la source
Avec C # 8, vous avez maintenant pratiquement l'héritage multiple via l'implémentation par défaut des membres de l'interface:
la source
new ConsoleLogger().Log(someEception)
- cela ne fonctionnera tout simplement pas, vous devrez explicitement convertir votre objet en anILogger
pour utiliser la méthode d'interface par défaut. Son utilité est donc quelque peu limitée.Si vous pouvez vivre avec la restriction que les méthodes de IFirst et ISecond ne doivent interagir qu'avec le contrat de IFirst et ISecond (comme dans votre exemple) ... vous pouvez faire ce que vous demandez avec des méthodes d'extension. En pratique, c'est rarement le cas.
///
Donc, l'idée de base est que vous définissez l'implémentation requise dans les interfaces ... ce truc requis devrait prendre en charge l'implémentation flexible dans les méthodes d'extension. Chaque fois que vous devez "ajouter des méthodes à l'interface", vous ajoutez plutôt une méthode d'extension.
la source
Oui, utiliser Interface est un problème car chaque fois que nous ajoutons une méthode dans la classe, nous devons ajouter la signature dans l'interface. Et si nous avons déjà une classe avec un tas de méthodes mais pas d'interface? nous devons créer manuellement une interface pour toutes les classes dont nous voulons hériter. Et le pire, c'est que nous devons implémenter toutes les méthodes dans les interfaces de la classe enfant si la classe enfant doit hériter de l'interface multiple.
En suivant le modèle de conception de façade, nous pouvons simuler l'héritage de plusieurs classes à l'aide d' accesseurs . Déclarez les classes en tant que propriétés avec {get; set;} à l'intérieur de la classe qui doit hériter et toutes les propriétés et méthodes publiques proviennent de cette classe, et dans le constructeur de la classe enfant instanciez les classes parentes.
Par exemple:
avec cette structure, la classe Child aura accès à toutes les méthodes et propriétés de la classe Father and Mother, simulant l'héritage multiple, héritant d'une instance des classes parentes. Pas tout à fait pareil mais c'est pratique.
la source
Quick Actions and Refactorings...
c'est un must, cela vous fera gagner beaucoup de tempsNous semblons tous suivre le chemin de l'interface avec cela, mais l'autre possibilité évidente, ici, est de faire ce que la POO est censée faire, et de construire votre arbre d'héritage ... (n'est-ce pas ce que la conception de classe est tout à propos?)
Cette structure fournit des blocs de code réutilisables et, comment doit-on écrire le code POO?
Si cette approche particulière ne correspond pas tout à fait au projet de loi, nous créons simplement de nouvelles classes en fonction des objets requis ...
la source
L'héritage multiple est l'une de ces choses qui pose généralement plus de problèmes qu'il n'en résout. En C ++, cela correspond au modèle de vous donner suffisamment de corde pour vous accrocher, mais Java et C # ont choisi de suivre la voie la plus sûre de ne pas vous donner l'option. Le plus gros problème est de savoir quoi faire si vous héritez de plusieurs classes qui ont une méthode avec la même signature que l'héritier n'implémente pas. Quelle méthode de classe doit-elle choisir? Ou cela ne devrait-il pas être compilé? Il existe généralement une autre façon d'implémenter la plupart des choses qui ne repose pas sur l'héritage multiple.
la source
Si X hérite de Y, cela a deux effets quelque peu orthogonaux:
Bien que l'héritage prévoie les deux fonctionnalités, il n'est pas difficile d'imaginer des circonstances où l'une ou l'autre pourrait être utile sans l'autre. Aucun langage .net que je connaisse n'a un moyen direct d'implémenter le premier sans le second, bien que l'on puisse obtenir une telle fonctionnalité en définissant une classe de base qui n'est jamais utilisée directement, et en ayant une ou plusieurs classes qui en héritent directement sans rien ajouter new (ces classes pourraient partager tout leur code, mais ne seraient pas substituables les unes aux autres). Tout langage compatible CLR, cependant, permettra l'utilisation d'interfaces qui fournissent la deuxième fonctionnalité des interfaces (substituabilité) sans la première (réutilisation des membres).
la source
Je sais que je sais même si ce n'est pas autorisé et ainsi de suite, parfois vous en avez vraiment besoin pour ceux:
comme dans mon cas, je voulais faire cette classe b: Form (yep les windows.forms) classe c: b {}
car la moitié de la fonction était identique et avec l'interface, vous devez tous les réécrire
la source
class a : b, c
(implémentant tous les trous de contrat nécessaires). Peut-être que vos exemples sont un peu plus simplifiés?Étant donné que la question de l'héritage multiple (MI) apparaît de temps en temps, j'aimerais ajouter une approche qui résout certains problèmes avec le modèle de composition.
Je construis sur la
IFirst
,ISecond
,First
,Second
,FirstAndSecond
approche, comme il a été présenté dans la question. Je réduit l'exemple de code àIFirst
, car le modèle reste le même quel que soit le nombre d'interfaces / classes de base MI.Supposons qu'avec MI
First
etSecond
dérivent tous les deux de la même classe de baseBaseClass
, en utilisant uniquement les éléments d'interface publique deBaseClass
Cela peut être exprimé en ajoutant une référence de conteneur à
BaseClass
dans l' implémentationFirst
etSecond
:Les choses deviennent plus compliquées, lorsque les éléments d'interface protégés de
BaseClass
sont référencés ou quandFirst
etSecond
seraient des classes abstraites dans MI, nécessitant leurs sous-classes pour implémenter certaines parties abstraites.C # permet aux classes imbriquées d'accéder aux éléments protégés / privés de leurs classes contenantes, donc cela peut être utilisé pour lier les bits abstraits de l'
First
implémentation.Il y a pas mal de passe-partout impliqués, mais si la mise en œuvre réelle de FirstMethod et SecondMethod est suffisamment complexe et que la quantité de méthodes privées / protégées accessibles est modérée, alors ce modèle peut aider à surmonter le manque d'héritage multiple.
la source
Cela va dans le sens de la réponse de Lawrence Wenham, mais selon votre cas d'utilisation, cela peut ou non être une amélioration - vous n'avez pas besoin des poseurs.
Désormais, tout objet qui sait comment obtenir une personne peut implémenter IGetPerson et il disposera automatiquement des méthodes GetAgeViaPerson () et GetNameViaPerson (). À partir de ce moment-là, tout le code de la personne va dans IGetPerson, pas dans IPerson, à l'exception des nouveaux ivars, qui doivent aller dans les deux. Et en utilisant un tel code, vous n'avez pas à vous soucier de savoir si votre objet IGetPerson est lui-même réellement un IPerson.
la source
C'est désormais possible grâce aux
partial
classes, chacune d'elles peut hériter d'une classe à elle seule, faisant que l'objet final hérite de toutes les classes de base. Vous pouvez en savoir plus ici .la source