65 votes

Pourquoi le langage c# structs sont immuables ?

J’étais juste curieux de savoir pourquoi les structs, cordes etc. sont immuables ? Quelle est la raison pour faire leur immuable et reste des objets comme mutables. Quelles sont les choses qui sont censées rendre un objet immuable ?

Y at-il une différence sur la mémoire de la façon dont l’allocation et désallouée pour objets mutables et immuables ?

131voto

Eric Lippert Points 300275

Si ce sujet vous intéresse, j'ai un certain nombre d'articles sur la programmation immuable à http://blogs.msdn.com/b/ericlippert/archive/tags/immutability/

J'étais juste curieux de savoir pourquoi les structures, les chaînes, etc. sont-ils immuables?

Les structures et les classes ne sont pas immuables par défaut, mais il est conseillé d'effectuer les structures immuables. J'aime immuable classes de trop.

Les chaînes sont immuables.

Quelle est la raison de leur immuable et le reste des objets mutables.

Raisons de faire tous les types immuables:

  • Il est plus facile de raisonner sur des objets qui ne change pas. Si j'ai une file d'attente avec trois éléments en elle, je sais qu'il n'est pas vide, il n'était pas vide il ya cinq minutes, il ne sera pas vide dans l'avenir. Il est immuable! Une fois que je connais un fait, à ce sujet, je peux utiliser ce fait pour toujours. Faits sur des objets immuables ne pas aller rassis.

  • Un cas particulier du premier point: des objets immuables sont beaucoup plus facile de faire des threads. La plupart la sécurité des threads problèmes sont dus à l'écrit sur un fil et on lit sur l'autre; des objets immuables n'avez pas écrit.

  • Des objets immuables peuvent être démontés et réutilisés. Par exemple, si vous avez un immuable arbre binaire vous pouvez utiliser sa gauche et à droite de sous-arborescences que les sous-arbres de différentes arbre sans vous en soucier. Dans une mutable structure, vous finissent généralement par faire des copies de données pour la ré-utiliser parce que vous ne voulez pas les changements apportés à une logique de l'objet en affecter un autre. Cela peut vous faire économiser beaucoup de temps et de mémoire.

Des raisons pour lesquelles les structures immuables

Il y a beaucoup de raisons pour faire des structures immuables. Voici juste un.

Les structures sont copiés par valeur et non par référence. Il est facile de par inadvertance traiter une structure comme étant copiés 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 revoir certaines de ce code dans une méthode d'aide:

void Helper(S s)
{
    ... lots of code ...
    s.Mutate();
    ... lots more code ...
}

FAUX! Qui devrait être (ref S) -- si vous ne le faites pas alors la mutation qui va se passer sur une copie de la s. Si vous ne laissez pas les mutations en premier lieu, puis toutes ces sortes de problèmes disparaissent.

Raisons pour faire de chaînes immuable

Souvenir de mon premier point sur les faits au sujet de immuable structures de rester dans les faits?

Supposons que les cordes étaient mutable:

public static File OpenFile(string filename)
{
    if (!HasPermission(filename)) throw new SecurityException();
    return InternalOpenFile(filename);
}

Que faire si l'hostilité de l'appelant mute nom du fichier après le contrôle de sécurité et avant que le fichier est ouvert? Le code vient d'ouvrir un fichier qu'ils pourraient ne pas avoir l'autorisation de!

Encore une fois, de données mutable est difficile de raisonner sur. Vous voulez que le fait "le présent de l'appelant est autorisé à voir le fichier décrit par cette chaîne" pour être vrai pour toujours, pas jusqu'à ce qu'une mutation se produit. Avec les cordes mutables, d'écrire du code sécurisé nous avions constamment à faire des copies de données que nous savons ne pas changer.

Quelles sont les choses qui sont envisagées pour rendre un objet immuable?

Le type logiquement représenter quelque chose qui est "éternelle" de la valeur? Le nombre 12 est le nombre de 12; elle ne change pas. Entiers doivent être immuables. Le point (10, 30) est le point (10, 30); elle ne change pas. Les Points devraient être immuable. La chaîne "abc" est la chaîne "abc"; elle ne change pas. Les chaînes doivent être immuable. La liste (10, 20, 30) ne change pas. Et ainsi de suite.

Parfois, le type représente des choses qui changent. Mary Smith, du nom est Smith, mais demain, elle pourrait être Mary Jones. Ou Mlle Smith aujourd'hui peut-être Docteur Smith demain. L'étranger a cinquante points de santé maintenant, mais a dix après avoir été frappé par le faisceau laser. Certaines choses sont mieux représentés que les mutations.

Est-il une différence sur la façon dont la mémoire est allouée et libéré pour mutable et des objets immuables?

Pas en tant que tel. Comme je l'ai mentionné avant que, une des belles choses au sujet des valeurs inaltérables, c'est que quelque chose que vous pouvez ré-utiliser des parties d'entre eux, sans en faire des copies. Donc, dans ce sens, l'allocation de mémoire peuvent être très différentes.

9voto

Justin Niessner Points 144953

Les structures non...c'est pourquoi les structures mutables sont le mal.

La création d'mutable structs peut conduire à toutes sortes de comportement étrange de votre demande et, par conséquent, ils sont considérés comme une très mauvaise idée (provenant du fait qu'ils ressemblent à un type de référence, mais sont en fait un type de valeur et seront copiés à chaque fois que vous passez autour).

Cordes, d'autre part, sont. Cela les rend intrinsèquement thread-safe et permet des optimisations via la chaîne de stage. Si vous avez besoin de construire un complexe de chaîne à la volée, vous pouvez utiliser StringBuilder.

5voto

supercat Points 25534

Les concepts de la mutabilité et de l'immuabilité ont des significations différentes lorsqu'il est appliqué à des structures et des classes. Un aspect clé (souvent, la clé de la faiblesse) des mutable classes est si Foo a un champ Bar de type List<Integer>, qui contient une référence à une liste contenant (1,2,3), un autre code qui a une référence à cette même liste pourrait le modifier, tels que Bar contient une référence à une liste contenant (4,5,6), même si ce code n'a aucun accès à l' Bar. En revanche, si Foo eu Biz de type System.Drawing.Point, la seule façon que tout peut modifier n'importe quel aspect de l' Biz serait d'avoir accès en écriture à ce champ.

Les champs (public et privé) d'une structure peut être muté par du code qui peut muter l'emplacement de stockage dans lequel la structure est stocké, et ne peut pas être muté par du code qui ne peut pas muter l'emplacement de stockage où il est stocké. Si toutes les données encapsulées dans une struct est tenue dans ses champs, une telle structure permet d'associer le contrôle d'un immuable type avec la commodité d'une mutable type, à moins que la structure est codé de telle manière à supprimer de telles commodité (une habitude qui, malheureusement, Microsoft certains programmeurs recommander).

Le "problème" avec les structures, c'est que lorsqu'une méthode (y compris une propriété de la mise en œuvre) est invoquée sur une structure en lecture seule de contexte (ou immuable emplacement), le système copie les struct, effectue la méthode sur la copie temporaire, et rejette le résultat. Ce comportement a conduit les programmeurs de mettre en avant la malheureuse idée que la façon d'éviter les problèmes liés à une mutation des méthodes est d'avoir de nombreuses structures interdire par morceaux mises à jour, lorsque les problèmes auraient pu être mieux éviter en remplaçant simplement les propriétés apparentes champs.

D'ailleurs, certaines personnes se plaignent que quand une propriété de classe renvoie une pratique mutable struct, les changements de la structure n'affectent pas la classe à partir de laquelle il est venu. Je postulons que c'est une bonne chose, le fait que le produit retourné est une structure rend le comportement clair (surtout si c'est un exposé-champ struct). Comparer un extrait à l'aide d'un hypothétique struct et bien sur Drawing.Matrix avec un l'aide d'une réelle propriété de classe mis en place par Microsoft:

// Hypothétique struct
public struct {
 public float xx,xy,yx,yy,dx,dy;
} Transform2d;

// Hypothétique propriété du Système".De dessin.Drawing2d.La matrice"
public Transform2d Transformer {get;}

// Réelle de la propriété de "le Système de.De dessin.Drawing2d.La matrice"
public float[] Éléments { get; }

// Code à l'aide hypothétique struct
Transform2d myTransform = myMatrix.Transformer;
myTransform.dx += 20;
... un autre code à l'aide de myTransform

// Code à partir de la propriété de Microsoft
float[] montableau = myMatrix.Éléments;
montableau[4] += 20;
... un autre code à l'aide de myArray

En regardant la réelle propriété de Microsoft, est-il possible de dire si l'écriture d' myArray[4] affectera myMatrix? Même en regardant la page http://msdn.microsoft.com/en-us/library/system.drawing.drawing2d.matrix.elements.aspx est-il possible d'en parler? Si la propriété avait été écrite à l'aide de la structure de la base de l'équivalent, il n'y aurait pas de confusion; la propriété qui retourne la structure serait de retour ne sont ni plus ni moins que la valeur actuelle de six chiffres. Évolution myTransform.dx serait ni plus ni moins d'une écriture à une variable à virgule flottante qui a été seules à autre chose. Quelqu'un qui n'aime pas le fait que le changement de myTransform.dx n'affecte pas myMatrix devraient l'être tout autant agacé que l'écriture myArray[4] n'affecte pas myMatrix , soit, à l'exception que l'indépendance de l' myMatrix et myTransform est apparent, alors que l'indépendance de l' myMatrix et myArray ne l'est pas.

4voto

Hans Passant Points 475940

Un type struct n’est pas immuable. Oui, les chaînes sont. Faire votre propre type immuable est facile, simplement ne fournir un constructeur par défaut, faire tous les champs privés et ne définir aucune méthodes ou propriétés qui modifient la valeur d’un champ. Disposer d’une méthode qui devrait muter le retour de l’objet un nouvel objet à la place. Il y a un angle de gestion de mémoire, vous avez tendance à créer un grand nombre de copies et d’ordures.

1voto

Strilanc Points 7161

Les structs peuvent être mutables, mais c’est une mauvaise idée parce qu’ils ont copie-sémantique. Si vous apportez une modification à un struct, vous pourriez effectivement modifier une copie. Il est très délicate de conserver une trace d’exactement ce qui a été changé.

Structs mutables reproduisent les erreurs.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X