Comment les ValueTypes dérivent-ils de Object (ReferenceType) et sont-ils toujours des ValueTypes?

C # ne permet pas aux structs de dériver des classes, mais tous les ValueTypes dérivent d’Object. Où est cette distinction faite?

Comment le CLR gère-t-il cela?

C # ne permet pas aux structures de dériver des classes

Votre déclaration est incorrecte, d’où votre confusion. C # permet aux structures de dériver des classes. Toutes les structures dérivent de la même classe, System.ValueType, qui dérive de System.Object. Et toutes les énumérations dérivent de System.Enum.

MISE À JOUR: Il y a eu une certaine confusion dans certains commentaires (maintenant supprimés), ce qui justifie une clarification. Je vais poser quelques questions supplémentaires:

Les structures proviennent-elles d’un type de base?

Tout à fait oui. Nous pouvons le voir en lisant la première page du cahier des charges:

Tous les types C #, y compris les types primitifs tels que int et double, héritent d’un seul type d’object racine.

Maintenant, je remarque que la spécification exagère le cas ici. Les types de pointeurs ne dérivent pas de l’object et la relation de dérivation pour les types d’interface et les types de paramètre de type est plus complexe que ce que cette esquisse indique. Cependant, tous les types de structure dérivent clairement d’un type de base.

Y a-t-il d’autres façons de savoir que les types de structure dérivent d’un type de base?

Sûr. Un type de structure peut remplacer ToSsortingng . Qu’est-ce qui prévaut, sinon une méthode virtuelle de son type de base? Par conséquent, il doit avoir un type de base. Ce type de base est une classe.

Puis-je dériver une structure définie par l’utilisateur à partir d’une classe de mon choix?

Plutôt non Cela n’implique pas que les structures ne dérivent pas d’une classe . Les structures dérivent d’une classe et héritent ainsi des membres héritables de cette classe. En fait, les structures doivent dériver d’une classe spécifique: les énumérations doivent être dérivées de Enum , les structures doivent être dérivées de ValueType . Dans la mesure où ceux-ci sont requirejs , le langage C # vous interdit d’indiquer la relation de dérivation dans le code.

Pourquoi l’interdire?

Lorsqu’une relation est requirejse , le concepteur de langage a des options: (1) obliger l’utilisateur à saisir l’incantation requirejse, (2) le rendre facultatif ou (3) l’interdire. Chacun a ses avantages et ses inconvénients, et les concepteurs de langage C # ont choisi différemment selon les détails spécifiques de chacun.

Par exemple, les champs const doivent être statiques, mais il est interdit de dire qu’ils le sont parce que cela est le premier, un verbiage inutile, et deuxièmement, il existe des champs const non statiques. Mais les opérateurs surchargés doivent être marqués comme statiques, même si le développeur n’a pas le choix. il est trop facile pour les développeurs de croire qu’une surcharge d’opérateur est une méthode d’instance différente. Cela remplace la préoccupation selon laquelle un utilisateur peut en venir à croire que le “statique” implique que dire “virtuel” est également une possibilité.

Dans ce cas, exiger d’un utilisateur qu’il dise que sa structure dérive de ValueType semble être un simple verbiage excessif, et cela implique que la structure peut dériver d’un autre type. Pour éliminer ces deux problèmes, C # rend illégal d’indiquer dans le code qu’une structure dérive d’un type de base, bien que ce soit clairement le cas.

De même, tous les types de délégué dérivent de MulticastDelegate , mais C # vous oblige à ne pas le dire.

Donc, maintenant, nous avons établi que toutes les structures en C # dérivent d’une classe .

Quelle est la relation entre l’ inheritance et la dérivation d’une classe ?

Beaucoup de gens sont confus par la relation d’inheritance en C #. La relation d’inheritance est assez simple: si une structure, une classe ou un délégué de type D dérive d’une classe de type B, les membres héritables de B sont également membres de D. C’est aussi simple que cela.

Qu’est-ce que cela signifie en ce qui concerne l’inheritance quand on dit qu’une structure dérive de ValueType? Simplement que tous les membres héritables de ValueType sont également membres de la structure. Voici comment les structures obtiennent leur implémentation de ToSsortingng , par exemple; il est hérité de la classe de base de la structure.

Tous les membres héritables? Sûrement pas. Les membres privés sont-ils héritables?

Oui. Tous les membres privés d’une classe de base sont également membres du type dérivé. Il est illégal d’appeler ces membres par leur nom si le site d’appel n’est pas dans le domaine de l’ accessibilité du membre. Ce n’est pas parce que vous avez un membre que vous pouvez l’utiliser!

Nous continuons maintenant avec la réponse originale:


Comment le CLR gère-t-il cela?

Extrêmement bien. 🙂

Ce qui fait qu’un type de valeur est un type de valeur, c’est que ses instances sont copiées par valeur . Ce qui fait qu’un type de référence est un type de référence, c’est que ses instances sont copiées par référence . Vous semblez croire que la relation d’ inheritance entre les types de valeur et les types de référence est particulière et inhabituelle, mais je ne comprends pas ce qu’est cette croyance. L’inheritance n’a rien à voir avec la façon dont les choses sont copiées.

Vois-le de cette façon. Supposons que je vous ai dit les faits suivants:

  • Il existe deux types de boîtes, les boîtes rouges et les boîtes bleues.

  • Chaque case rouge est vide.

  • Il existe trois boîtes bleues spéciales appelées O, V et E.

  • O n’est pas dans une boîte.

  • V est à l’intérieur de O.

  • E est à l’intérieur de V.

  • Aucune autre boîte bleue n’est à l’intérieur de V.

  • Aucune boîte bleue à l’intérieur de E.

  • Chaque boîte rouge est en V ou en E.

  • Chaque boîte bleue autre que O est elle-même dans une boîte bleue.

Les boîtes bleues sont des types de référence, les boîtes rouges sont des types de valeur, O est System.Object, V est System.ValueType, E est System.Enum et la relation “dedans” est “dérivée de”.

C’est un ensemble de règles parfaitement cohérent et simple que vous pourriez facilement mettre en œuvre si vous aviez beaucoup de carton et beaucoup de patience. Qu’une boîte soit rouge ou bleue n’a rien à voir avec ce qu’elle contient; dans le monde réel, il est parfaitement possible de mettre une boîte rouge dans une boîte bleue. Dans le CLR, il est parfaitement légal de créer un type de valeur qui hérite d’un type de référence, à condition qu’il s’agisse de System.ValueType ou de System.Enum.

Alors reformulons votre question:

Comment les ValueTypes dérivent-ils de Object (ReferenceType) et sont-ils toujours des ValueTypes?

comme

Comment est-il possible que chaque case rouge (types de valeur) se trouve dans (dérive de) la case O (System.Object), qui est une case bleue (un type de référence) et soit toujours une case rouge (un type de valeur)?

Quand vous le dites comme ça, j’espère que c’est évident. Rien ne vous empêche de mettre une boîte rouge à l’intérieur de la boîte V, qui se trouve à l’intérieur de la case O, qui est bleue. Pourquoi y en aurait-il?


Une mise à jour supplémentaire:

La question initiale de Joan était de savoir comment il est possible qu’un type de valeur dérive d’un type de référence. Ma réponse initiale n’expliquait pas vraiment les mécanismes utilisés par le CLR pour expliquer le fait que nous avons une relation de dérivation entre deux éléments ayant des représentations complètement différentes, à savoir si les données référencées ont un en-tête d’object, une sync block, s’il possède son propre stockage pour les besoins de la récupération de place, etc. Ces mécanismes sont compliqués, trop compliqués à expliquer en une seule réponse. Les règles du système de type CLR sont un peu plus complexes que son aspect quelque peu simplifié que nous voyons en C #, où il n’existe pas de distinction nette entre les versions encadrées et les versions non classées d’un type, par exemple. L’introduction des génériques a également engendré une complexité supplémentaire considérable. Consultez la spécification de la CLI pour plus de détails, en accordant une attention particulière aux règles de boxe et aux appels virtuels limités.

Ceci est une construction quelque peu artificielle maintenue par le CLR afin de permettre à tous les types d’être traités comme un System.Object.

Les types de valeur dérivent de System.Object via System.ValueType , qui est l’endroit où la gestion spéciale se produit (c’est-à-dire que le CLR gère la boxing / unboxing, etc. pour tout type dérivant de ValueType).

Petite correction, C # ne permet pas aux structs de personnaliser quelque chose, pas seulement les classes. Tout ce qu’une structure peut faire, c’est implémenter une interface très différente de la dérivation.

Je pense que la meilleure façon de répondre est que ValueType est spécial. C’est essentiellement la classe de base pour tous les types de valeur dans le système de type CLR. Il est difficile de savoir comment répondre “comment le CLR gère-t-il cela” car c’est simplement une règle du CLR.

Votre déclaration est incorrecte, d’où votre confusion. C # permet aux structures de dériver des classes. Toutes les structures dérivent de la même classe, System.ValueType

Alors essayons ceci:

  struct MyStruct : System.ValueType { } 

Ce ne sera même pas comstackr. Le compilateur vous rappellera “Type” System.ValueType “dans la liste d’interface n’est pas une interface”.

Lorsque décomstackr Int32 qui est une structure, vous trouverez:

public struct Int32: IComparable, IFormattable, IConvertible {}, sans mentionner qu’il est dérivé de System.ValueType. Mais dans le navigateur d’object, vous trouvez qu’Int32 hérite de System.ValueType.

Alors tout cela me fait croire:

Je pense que la meilleure façon de répondre est que ValueType est spécial. C’est essentiellement la classe de base pour tous les types de valeur dans le système de type CLR. Il est difficile de savoir comment répondre “comment le CLR gère-t-il cela” car c’est simplement une règle du CLR.

Un type de valeur encadré est en fait un type de référence (il marche comme un et charrie comme tel, si bien qu’il en est un). Je suggère que ValueType n’est pas vraiment le type de base des types de valeur, mais plutôt le type de référence de base auquel les types de valeur peuvent être convertis lorsqu’ils sont convertis en type Object. Les types de valeur non encadrés sont en dehors de la hiérarchie des objects.