Pourquoi une classe ne peut-elle pas étendre sa propre classe nestede en C #?

Par exemple:

public class A : AB { public class B { } } 

Qui génère cette erreur du compilateur:

Dépendance de classe de base circulaire impliquant ‘A’ et ‘A.B’

J’ai toujours pensé qu’une classe nestede se comportait comme une classe normale, à l’exception de règles spéciales concernant l’access aux membres privés de la classe externe, mais j’imagine qu’il existe un inheritance implicite entre les deux classes?

Autant que je sache, il n’y a pas d’inheritance implicite. Je me serais attendu à ce que tout se passe bien, même si je peux imaginer l’étranglement si A et B étaient génériques.

C’est spécifié dans la section 10.1.4 de la spécification:

Lorsqu’une classe B dérive d’une classe A, il s’agit d’une erreur de compilation lorsque A dépend de B. Une classe dépend directement de sa classe de base directe (le cas échéant) et directement de la classe dans laquelle elle est immédiatement nestede ( si seulement). Étant donné cette définition, l’ensemble complet des classes dont dépend une classe est la fermeture transitive de la relation dépend directement de la relation.

J’ai mis en évidence la section pertinente.

Cela explique pourquoi le compilateur le rejette, mais pas pourquoi le langage l’interdit. Je me demande s’il y a une ressortingction CLI …

EDIT: Ok, j’ai eu une réponse d’Eric Lippert. En gros, ce serait techniquement possible (rien n’interdit cela dans la CLI), mais:

  • Le permettre serait difficile dans le compilateur, invalider diverses hypothèses actuelles concernant la commande et les cycles
  • C’est une décision de conception assez étrange qui est plus facile à interdire qu’à soutenir

Il a également été noté sur le fil de discussion que cela rendrait ce genre de chose valide:

 AB x = new ABBBBBBBBBBBB(); 

… mais cela serait déjà valable (comme l’a noté Tinister) si B dérive de A.

Nidification + inheritance = étrangeté …

Ce n’est pas une chose C # autant que c’est une chose de compilateur. L’un des travaux d’un compilateur est de disposer une classe en mémoire, c’est-à-dire un ensemble de types de données de base, de pointeurs, de pointeurs de fonction et d’autres classes.

Il ne peut pas construire la mise en page pour la classe A tant qu’il ne sait pas quelle est la mise en page de la classe B. Il ne peut pas savoir quelle est la présentation de la classe B avant d’avoir terminé avec celle de la classe A. Dépendance circulaire.

Je pense que l’imbrication est censée représenter que le type nested fait partie de la définition du type d’imbrication. Avec cette interprétation, la limitation a du sens car au moment où le compilateur répond à la définition de A, AB n’est pas encore défini, et même à la fin de A, il est déjà défini en termes de AB.

En ce qui concerne les questions sur ce que je tentais de faire:

En gros, je voulais créer une classe qui avait une relation de composition avec elle-même, mais je ne voulais pas que l’object contenu contienne d’autres objects et donc crée une chaîne avec beaucoup de “A has-a A has-a has- a a-a … “relations. Donc, ma pensée à l’époque était de faire quelque chose comme ça:

 public class A : A.AA { public class AA { // All of the class's logic } private AA _containedObject; } 

Ce qui, à l’époque, semblait assez glissant mais, rétrospectivement, je n’en suis pas si sûr …

J’avais fouillé dans Google et n’avais trouvé aucune bonne discussion à ce sujet; j’ai donc pensé la poster ici.

Cependant, dans les commentaires d’un article sur le blog d’Eric Lippert, il donne des exemples d’une classe implémentant une interface nestede, ainsi qu’une classe implémentant une interface générique avec une classe nestede comme argument de type (qui ne comstack pas et appelle ” bug “dans le compilateur actuel). Ces deux exemples concernent les interfaces, je me demandais donc s’il existait des règles spéciales avec des classes nestedes. Et il semble qu’il y en ait.

J’ai pu éviter cela (au moins avec les interfaces) en héritant d’une classe séparée contenant les interfaces nestedes. (Dans mon scénario, je renvoie également des références à ces interfaces.)

Au lieu de:

 public class MyClass : MyClass.Interface where T1 : ... where T2 : ... where T3 : ... { public interface Interface { Interface SomeMethod(); } Interface Interface.SomeMethod() { ... } } // comstack error: Circular base class dependency 

Faites quelque chose comme ça:

 public sealed class MyClassInterfaces where T1 : ... where T2 : ... where T3 : ... { public interface Interface { Interface SomeMethod(); } } sealed class MyClass : MyClassInterfaces.Interface where T1 : ... where T2 : ... where T3 : ... { MyClassInterfaces.Interface MyClassInterfaces.Interface.SomeMethod() { ... } } 

Pour éviter la laideur des implémentations d’interface explicites, vous pouvez également hériter de l’autre classe, mais cela ne fonctionnerait pas si vous tentiez d’hériter d’une classe nestede, car vous ne pouvez pas hériter des deux classes.

 public abstract class MyClassInterfaces where T1 : ... where T2 : ... where T3 : ... { public interface Interface { Interface SomeMethod(); } } sealed class MyClass : MyClassInterfaces, MyClassInterfaces.Interface where T1 : ... where T2 : ... where T3 : ... { Interface Interface.SomeMethod() { ... } } 

Cela n’a aucun sens pour moi … Vous essayez d’étendre quelque chose qui n’existe pas !!! La classe B n’existe que dans le cadre de la classe A et, à cause de cela, je pense qu’il existe une sorte d’inheritance.