J’étais juste curieux de savoir pourquoi les structs, les chaînes, etc. sont immuables? Quelle est la raison de les rendre immuables et le rest des objects comme mutables. Quelles sont les choses qui sont considérées comme rendant un object immuable?
Y a-t-il une différence sur la façon dont la mémoire est allouée et libérée pour les objects mutables et immuables?
Si ce sujet vous intéresse, j’ai un certain nombre d’articles sur la programmation immuable sur http://blogs.msdn.com/b/ericlippert/archive/tags/immutability/
J’étais juste curieux de savoir pourquoi les structs, les chaînes, etc. sont immuables?
Les structures et les classes ne sont pas immuables par défaut, bien qu’il soit recommandé de rendre les structures immuables. J’aime aussi les classes immuables.
Les chaînes sont immuables.
Quelle est la raison de les rendre immuables et le rest des objects comme mutables.
Il est plus facile de raisonner sur des objects qui ne changent pas. Si j’ai une queue avec trois éléments, je sais qu’elle n’est pas vide maintenant, elle n’était pas vide il y a cinq minutes, elle ne sera plus vide dans le futur. C’est immuable! Une fois que je connais un fait à ce sujet, je peux utiliser ce fait pour toujours. Les faits sur les objects immuables ne sont pas vains.
Un cas particulier du premier point: les objects immuables sont beaucoup plus faciles à rendre threadsafe. La plupart des problèmes de sécurité des threads sont dus à l’écriture sur un thread et à la lecture sur un autre; les objects immuables n’ont pas d’écritures.
Les objects immuables peuvent être démontés et réutilisés. Par exemple, si vous avez un arbre binary immuable, vous pouvez utiliser ses sous-arbres gauche et droit en tant que sous-arborescence d’un arbre différent sans vous en soucier. Dans une structure modifiable, vous finissez généralement par faire des copies de données pour les réutiliser, car vous ne souhaitez pas que les modifications apscopes à un object logique en affectent une autre. Cela peut économiser beaucoup de temps et de mémoire.
Il y a beaucoup de raisons de rendre les structures immuables. En voici un.
Les structures sont copiées par valeur et non par référence. Il est facile de traiter accidentellement une structure comme étant copiée par référence. Par exemple:
void M() { S s = whatever; ... lots of code ... s.Mutate(); ... lots more code ... Console.WriteLine(s.Foo); ... }
Maintenant, vous voulez réorganiser une partie de ce code dans une méthode d’assistance:
void Helper(S s) { ... lots of code ... s.Mutate(); ... lots more code ... }
FAUX! Cela devrait être (ref S s) – si vous ne le faites pas alors la mutation se produira sur une copie de s. Si vous n’autorisez pas les mutations, tous ces problèmes disparaissent.
Rappelez-vous mon premier point concernant les faits concernant les structures immuables restant des faits?
Supposons que la chaîne soit mutable:
public static File OpenFile(ssortingng filename) { if (!HasPermission(filename)) throw new SecurityException(); return InternalOpenFile(filename); }
Que se passe-t-il si l’appelant hostile modifie le nom du fichier après le contrôle de sécurité et avant l’ouverture du fichier? Le code vient d’ouvrir un fichier pour lequel ils ne sont peut-être pas autorisés!
Encore une fois, les données mutables sont difficiles à raisonner. Vous voulez que le fait que cet appelant soit autorisé à voir le fichier décrit par cette chaîne soit vrai pour toujours , pas avant qu’une mutation ne se produise . Avec des chaînes modifiables, pour écrire du code sécurisé, nous devions constamment faire des copies des données que nous soaps ne pas changer.
Quelles sont les choses qui sont considérées comme rendant un object immuable?
Le type représente-t-il logiquement quelque chose qui est une valeur “éternelle”? Le nombre 12 est le nombre 12; ça ne change pas Les entiers doivent être immuables. Le point (10, 30) est le point (10, 30); ça ne change pas Les points doivent être immuables. La chaîne “abc” est la chaîne “abc”; ça ne change pas Les chaînes doivent être immuables. La liste (10, 20, 30) ne change pas. Etc.
Parfois, le type représente des choses qui changent. Le nom de famille de Mary Smith est Smith, mais demain elle pourrait être Mary Jones. Ou Mlle Smith aujourd’hui pourrait être le Docteur Smith demain. L’étranger a maintenant cinquante points de vie, mais il en a dix après avoir été touché par le rayon laser. Certaines choses sont mieux représentées comme des mutations.
Y a-t-il une différence sur la façon dont la mémoire est allouée et libérée pour les objects mutables et immuables?
Pas comme tel Comme je l’ai déjà dit, l’un des aspects positifs des valeurs immuables est que vous pouvez réutiliser des parties de ces valeurs sans faire de copies. En ce sens, l’allocation de mémoire peut être très différente.
Structs pas … c’est pourquoi les structures mutables sont mauvaises.
La création de structures mutables peut conduire à toutes sortes de comportements étranges dans votre application et, par conséquent, elles sont considérées comme une très mauvaise idée (du fait qu’elles ressemblent à un type de référence mais sont en réalité un type de valeur et seront autour d’eux).
Les cordes, par contre, sont. Cela les rend insortingnsèquement sûrs, tout en permettant des optimisations via l’internement de chaînes. Si vous avez besoin de construire une chaîne compliquée à la volée, vous pouvez utiliser SsortingngBuilder
.
Les concepts de mutabilité et d’immuabilité ont des significations différentes lorsqu’ils sont appliqués aux structures et aux classes. Un aspect clé (souvent, la principale faiblesse) des classes mutables est que Foo
ait un champ Bar
de type List
, qui contient une référence à une liste contenant (1,2,3), un autre code ayant une référence à cette même liste pourrait la modifier, de sorte que Bar
contienne une référence à une liste contenant (4,5,6), même si cet autre code n’a aucun access à Bar
. En revanche, si Foo
avait un champ Biz
de type System.Drawing.Point
, le seul moyen de modifier un aspect quelconque de Biz
serait d’avoir un access en écriture à ce champ .
Les champs (publics et privés) d’une structure peuvent être mutés par n’importe quel code pouvant modifier l’emplacement de stockage dans lequel la structure est stockée et ne peuvent pas être mutés par un code qui ne peut pas modifier l’emplacement de stockage. Si toutes les informations encapsulées dans une structure sont contenues dans ses champs, une telle structure peut effectivement combiner le contrôle d’un type immuable avec la commodité d’un type mutable, à moins que la structure ne soit codée de manière à supprimer cette commodité ( une habitude que, malheureusement, certains programmeurs Microsoft recommandent).
Le problème avec structs est que, lorsqu’une méthode (y compris une implémentation de propriété) est appelée sur une structure dans un contexte en lecture seule (ou emplacement immuable), le système copie la structure, exécute la méthode sur la copie temporaire et en silence rejette le résultat. Ce comportement a conduit les programmeurs à mettre en avant la notion malheureuse que la manière d’éviter les problèmes avec les méthodes de mutation est de faire en sorte que de nombreuses structures interdisent les mises à jour par morceaux lorsque les problèmes auraient pu être évités en remplaçant simplement les propriétés par des champs exposés .
Incidemment, certaines personnes se plaignent que lorsqu’une propriété de classe renvoie une structure facilement mutable, les modifications apscopes à la structure n’affectent pas la classe dont elle est issue. Je dirais que c’est une bonne chose – le fait que l’élément renvoyé soit une structure rend le comportement plus clair (surtout s’il s’agit d’une structure de champ exposé). Comparez un extrait de code en utilisant une structure hypothétique et une propriété sur Drawing.Masortingx
avec un utilisant une propriété réelle sur cette classe, tel Drawing.Masortingx
par Microsoft:
// Structure hypothétique structure publique { float public xx, xy, yx, yy, dx, dy; } Transform2d; // Propriété hypothétique de "System.Drawing.Drawing2d.Masortingx" Transform2d publique Transform {get;} // Propriété réelle de "System.Drawing.Drawing2d.Masortingx" float public [] Elements {get; } // Code en utilisant une structure hypothétique Transform2d myTransform = myMasortingx.Transform; myTransform.dx + = 20; ... autre code utilisant myTransform // Code utilisant la propriété Microsoft réelle float [] myArray = myMasortingx.Elements; myArray [4] + = 20; ... autre code utilisant myArray
En regardant la propriété Microsoft, y a-t-il un moyen de savoir si l’écriture dans myArray[4]
affectera myMasortingx
? Même en regardant la page http://msdn.microsoft.com/en-us/library/system.drawing.drawing2d.masortingx.elements.aspx, y a-t-il un moyen de le savoir? Si la propriété avait été écrite en utilisant l’équivalent basé sur la structure, il n’y aurait pas de confusion; la propriété qui renvoie la structure ne renverrait rien de plus ni moins que la valeur actuelle de six nombres. Changer myTransform.dx
ne serait ni plus ni moins qu’une écriture dans une variable à virgule flottante qui n’était pas attachée à autre chose. Toute personne qui n’aime pas le fait que changer myTransform.dx
n’affecte pas myMasortingx
devrait être tout aussi ennuyée que l’écriture de myArray[4]
n’affecte pas myMasortingx
plus myMasortingx
, sauf que l’indépendance de myMasortingx
et de myTransform
est apparente, tandis que l’indépendance de myMasortingx
et myArray
ne sont pas.
Un type de structure n’est pas immuable. Oui, les chaînes sont. Rendre votre propre type immuable est facile, ne fournissez simplement pas de constructeur par défaut, rendez tous les champs privés et ne définissez aucune méthode ou propriété modifiant une valeur de champ. Avoir une méthode qui devrait muter l’object renvoie un nouvel object à la place. Il existe un angle de gestion de la mémoire, vous avez tendance à créer beaucoup de copies et de déchets.
Les structures peuvent être mutables, mais c’est une mauvaise idée car elles ont une sémantique de copie. Si vous modifiez une structure, vous pouvez en fait modifier une copie. Garder une trace de ce qui a été modifié est très délicat.
Les structures Mutable génèrent des erreurs.