Je voudrais créer un type en C # avec une valeur comme la sémantique. Il est immuable et il a une faible empreinte mémoire. Cependant, il va principalement être accessible via une interface informatique. Dans ce cas, un type de valeur devrait être en boîte, ce qui signifie que la valeur réelle devrait être copiée de la pile au tas. Par conséquent, je me demande s'il y a un avantage à l'aide d'un type de valeur (struct) au lieu d'un type de référence (classe)?
Pour illustrer ma situation, je fournis l'exemple suivant d'une interface je voudrais utiliser presque exclusivement ce type à l'aide de l'interface existe-t-il un avantage dans l'utilisation de i code > avec des implémentations
référencesTypeImplementation code> et
valaettapeimplementation code>: p>
i code> comme p>
ValueTypeImplementation code> sur
référencesTypeImplementation p> p> p>
3 Réponses :
Y a-t-il un avantage à l'aide d'une appréciation de valeur par rapport à référencesTypeImplementtation? P> blockQuote>
Pas si vous allez l'utiliser via l'interface. Comme vous l'avez mentionné, cela enregistrera le type de valeur, ce qui annule toute amélioration potentielle des performances. P>
En outre, le fait que votre consommation principale attendue em> soit via l'interface suggérerait que vous attendez une sémantique de référence, qui suggère à nouveau qu'un
classe code> serait plus approprié dans ce cas. P>
Conversion d'une structure en une interface provoque la boxe. Appeler implicitement implémenté
Le membre sur une structure ne provoque pas de boxe: ici Dans votre cas, si vous pouvez travailler avec implication / appel implicite, vous êtes mieux à l'abri avec la structure depuis que vous en évipérez; P> (a) boxe p> (b) Aucun débit de mémoire supplémentaire (qui est applicable sur n'importe quelle allocation de type de référence). P> P>
Si type Une référence à l'instance (pour les types de classe) ou à une référence à un objet de tas détenant une copie de l'instance (pour les types de valeur) peut être stockée dans une variable de type L'instance (pour les types de valeur) ou une référence à celle-ci (pour les types de classe) peut être stockée dans une variable (ou un élément de champ, un élément de réseau ou un autre emplacement de stockage) d'un type générique qui est limité à Un emplacement de stockage d'un type de classe ou de type interface em> conserve une référence à un objet de démarrage ou retour à Types L'heure principale peut être utile qu'une structure de mise en oeuvre d'une interface est dans des cas où l'utilisation suivra le deuxième modèle ci-dessus. Par exemple, on pourrait avoir une méthode: p> dans cette situation, si on devait appeler alors l'appelant devra créer un nouvel objet de tas pour contenir la valeur La création d'objets de tas a un certain coût. Si vous faites quelque chose d'un type de valeur, vous éviterez la nécessité de créer des objets de tas pour maintenir la grande majorité des cas, cela peut être une grosse victoire. Si chaque instance créée nécessiterait la création d'un objet de démarrage pour contenir une copie, cependant (par exemple, une variable de type interface), l'avantage de type valeur s'évaporerait complètement. Si les instances nécessiteraient en moyenne la création de plusieurs objets de démarrage pour contenir des copies (chaque fois qu'un type est converti du type de tas sur le type de valeur et le dos, une nouvelle instance sera requise), à l'aide des types de valeur peut être beaucoup moins élevé. efficace que la construction d'une instance de type de classe à quel code pourrait transmettre une référence. p> p> FOO code> Implements
ibar code>, il existe deux façons par lesquelles les membres de
ibar code> peuvent être utilisés sur une instance de
Foo code>:
ibar code> p> li>
ibar code>. p> li>
ul>
null code>. Un emplacement de stockage d'une valeur de valeur primitive tiendra une collection de bits représentant sa valeur. Un emplacement de stockage d'un type de valeur non primitive conserve le contenu concaténé de tous ses champs d'instance publique et privé. Un emplacement de stockage d'un type générique
t code> tiendra une référence de tas si
t code> est un type de classe ou un type d'interface, une collection de bits représentant une valeur primitive si
t code> est un type de valeur primitive ou les valeurs concaténées d'un fichier
t code> si
t code> est un type de structure; Cette détermination est basée sur le type réel de
t code>, et non sur aucune de ses contraintes. p>
FOO code> et
ibar < / code>, stockage d'un
foo code> dans un
ibar code> entraînera la création d'un nouvel objet de tas qui tiendra le contenu concaténé de tous les domaines public et privé de
FOO code> et stockez une référence à cet objet de tas dans
ibar code>. Cet objet de tas va ensuite se comporter comme tout autre objet de tas em>, plutôt que comme un emplacement de stockage de type valeur. Avoir des choses qui se comportent parfois comme des types de valeur et parfois comme des types de classe peuvent être déroutants; Il est préférable d'éviter une telle sémantique mixte lorsque cela est possible. p>
comteUniquethings (4, 6, 6) code>, le Système pourrait appeler le
Iequatable
System.int32 code>. Si la méthode avait été déclarée au lieu d'être déclarée: p>
int32 code> 4, une seconde Pour contenir la valeur 6, un tiers qui tiendrait également la valeur 6, et il faudrait alors passer des références à ces objets à la méthode code> compteur code>. Icky. P>
En tant que note, veillez à croire / perpétuer des simplications étroites de types de valeur et de la pile. blogs.msdn. COM / B / ERICLIPPERT / Archive / 2010/09/30 / ...
Personnellement, je n'utiliserais pas une interface pour un type immuable avec une sémantique de valeur. Pour commencer, il est impossible de garantir à client i> code que les valeurs du type "immuable" ne changeront pas. (Si vous avez besoin de moyens spéciaux de faire des instances du type, vous pouvez toujours utiliser des classes d'usine bien sûr.) Mais je trouve que les interfaces pour des types immuables simples avec une sémantique de valeur ne sont tout simplement pas utiles en raison des inconvénients.
Dupliqué possible de structs, interfaces et boxe
Voir aussi: Stackoverflow.com/Questions/3032750/...
Un bénéfice à l'utilisation d'un type de valeur est que vous pouvez les emballer plus efficacement en grandes matrices (en supposant qu'elles sont stockées comme la structure sous-jacente à une couche plutôt que par référence d'interface.) Je ne considérerais pas cela une raison impérieuse, cependant, à moins que Vous avez trouvé que la consommation de mémoire est un problème et que vous attendez de très grandes tableaux.
@Matthewwatson: Bien que possible pour les types de classe d'implémenter
Iequatable code>, cette interface est la plus précieuse dans les cas où
t code> est un type de valeur (il a une légère valeur pour scellée types de classe et ne doivent pas être mis en œuvre par des types de classe ouvertement inhéritables)
@supercat J'étais plus préoccupé par la fausse immuabilité.
@Matthewwatson: L'utilité des interfaces découle du fait que, comme une question de pratique i>, les classes sont généralement codées uniquement pour implémenter des interfaces lorsque leur comportement correspond au comportement documenté associé à ces interfaces. Une routine de tri qui accepte un
icomparer code> est autorisé à supposer que si
comparer (x, y) code> est positif,
comparer (y, x) Le code> sera négatif, mais il n'ya aucun moyen que l'interface
icomparable code> peut appliquer une telle chose.
@Matthewwatson: Si l'on avait des interfaces
IReadblematrix code> et
iimmutablematrix: IReadableMatrix code> avec des propriétés en lecture seule
int hauteur code>,
int largeur code> et
t ceci [int ligne, int Colonne] code>, la documentation de ce dernier pourrait spécifier qu'une instance de ce dernier doit être immuable tant que toute référence existe depuis longtemps que toute référence existe . Notez qu'une instance d'un type mis en œuvre par ex.
iImmutablematrix Code> et a signalé que ses dimensions de 10 000 par 10 000 peuvent nécessiter un stockage considérable moins (éventuellement par un facteur de plus d'un million) que ce serait un éventail de ces dimensions.
@supercat en effet, et
icomparable code> doit être une interface parce que les classes doivent la mettre en œuvre avec d'autres interfaces - mais d'autres classes ne doivent pas i> besoin Pour être des interfaces - en particulier des classes immuables avec une sémantique de valeur - et peut donc être garantie d'être immuable si vous avez tellement choisi. Je suppose que je me penche davantage vers la capacité de pouvoir être capable de prouver mathématiquement l'exactitude des programmes et de vous assurer que tout fonctionne tout au long de la convention et des tests unitaires. C'est bien bien sûr - nous avons besoin des deux!
@MatthewwatStson: Utilisation d'une classe scellée
immutablablatrix code> qui encapsule un tableau au lieu d'utiliser une interface
iimmutablematrix code> empêcherait le code extérieur de passer dans un objet qui implémente l'interface de manière contraire à Son contrat, mais obligerait également l'utilisation d'un réseau important pour tenir la matrice, même lorsque d'autres approches pourraient être littéralement un million de fois plus efficaces (bien que 1 000 000: 1 amélioration serait rare, 1 000: 1 amélioration pourrait ne pas être).
@supercat, je ne m'attendrais pas à ce qu'une grande matrice ait une sémantique de valeur. Je pense plus dans les lignes de
complexes code>