7
votes

Dictionnaire vraiment immuable dans .NET

Bonjour, après-midi ou nuit,

Immeuble toujours sur ma question à propos de Dictionnaires immuables dans .NET, j'ai proposé la question suivante : tandis que si alors tkey et tvalue sont des types de valeur que vous pouvez faire un dictionnaire vraiment immuable, dans le sens où ni sa structure interne ni les valeurs elles-mêmes ne peuvent changer, si ces paramètres sont types de référence les clés et les valeurs peuvent facilement être modifiés, changeant ainsi le dictionnaire lui-même. Ai-je raison?

Merci beaucoup.


5 commentaires

Si vous recherchez une implémentation ReadOnlydictionner , regardez ici: bit.ly/ecgwhz.


Oui, tu as raison. Si vous êtes programmé en C, vous avez un INT * Const PTR. Vous souhaitez avoir un const int * consonst PTR. Vous ne pouvez pas l'avoir dans C #, à moins que votre contrat d'objet spécifier l'objet est immuable.


Un type de référence peut être immuable ASWELL, l'immuabilité n'est pas particulière pour les types de valeur.


@MattDavey: Oui, un type de référence peut être immuable mais ce n'est pas requis être. Le problème Miguel décrit n'est pas qu'il n'y a pas de types de référence immuables, c'est qu'il y a sont des types de référence mutable .


@Miguel juste une note latérale: vous avez probablement fini de mettre en œuvre votre dictionnaire immuable maintenant. Mais vous pourriez être intéressé par mon propre dictionnaire immuable, Carte , qui possède des caractéristiques et des propriétés algorithmiques uniques, et un type de frère de sotage mutable intéressant, mmap .


6 Réponses :


2
votes

Les structures sont des types de valeur et ne sont pas nécessairement immuables - la réponse est donc non. Vous pouvez concevoir des types immuables (faire tous les champs et les propriétés en lecture-jour). Cependant, il n'y a pas de contrainte de type disponible (comme où tkey: classe ) qui vous permettrait de le faire respecter.

mise à jour : exemple: xxx

un peu construit j'avouerais.


5 commentaires

Vous pouvez ajouter un endroit où Thkey: la contrainte de type de valeur, puis dans la requête du constructeur, ils sont Thkey Type pour un attribut immutable par réflexion.


Sauf si elle est appliquée par le compilateur, vous ne gagnez pas vraiment autant. Je suppose que vous pouvez écrire un outil qui fonctionne comme une étape post-construction et vérifie si les types marqués d'un attribut immuable sont vraiment immuables, mais il peut devenir assez difficile. Contraignant tkey à la valeur Type ne change pas cela.


Si quelqu'un a étiqueté une classe / une structure avec immutatableattribute qui devrait suffire, si leur objet immuable n'est pas réellement immuable, c'est leur faute. En tant qu'auteur du dictionnaire, vous ne pouvez pas assumer la responsabilité de chaque type possible qu'il pourrait contenir.


Chriswue, alors que si le type de valeur est mutable? Comment ça va être muté dans le dictionnaire immuable ? Un type de valeur ne peut être muté que par la mutation de la variable qui le contient, et si le dictionnaire immuable n'expose aucune de ses variables internes à ses appelants, ils n'ont aucune possibilité de muter les types de valeur.


MH, mais vous pouvez casser l'immuabilité du type de valeur. Certes, ce n'est que si vous vous souciez d'une imputabilité profonde. `



1
votes

Voici un design très rapide, probablement ne compilera probablement pas tout de suite, mais j'espère vous donner quelques idées ...

[Immutable]
class ImmutableDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
    public ImmutableDictionary(IEnumerable<KeyValuePair<TKey, TValue>> keysValues)
    {
        // Ensure TKey is immutable...
        if (typeof(TKey).GetCustomAttribute(typeof(ImmutableAttribute), false).Length == 0)
            throw new InvalidOperationException(String.Format("Type '{0}' must be immutable.", typeof(TKey).AssemblyQualifiedName);

        // Ensure TValue is immutable...
        if (typeof(TValue).GetCustomAttribute(typeof(ImmutableAttribute), false).Length == 0)
            throw new InvalidOperationException(String.Format("Type '{0}' must be immutable.", typeof(TValue).AssemblyQualifiedName);

        foreach(var keyValue in keysValues)
            base.Add(keyValue.Key, keyValue.Value);
    }

    public new void Add(TKey key, TValue value)
    {
        throw new InvalidOperationException("Cannot modify contents of immutable dictionary.");
    }

    public new void Clear()
    {
        throw new InvalidOperationException("Cannot modify contents of immutable dictionary.");
    }

    public new void Remove(TKey key)
    {
        throw new InvalidOperationException("Cannot modify contents of immutable dictionary.");
    }

    public TValue this[TKey key]
    {
        get { return base[key]; }
        set
        {
            throw new InvalidOperationException("Cannot modify contents of immutable dictionary.");
        }
    }
}


0 commentaires

25
votes

Si alors Thkey et TValue sont des types de valeur, vous pouvez créer un dictionnaire vraiment immuable, dans le sens où ni sa structure interne ni les valeurs elles-mêmes ne peuvent changer, si ces paramètres sont des types de types de référence et que les valeurs peuvent facilement être modifiées, changeant ainsi le dictionnaire lui-même. Ai-je raison?

Pas exactement. Vous avez identifié un vrai problème, mais votre caractérisalisation n'est pas complètement réfléchie.

Tout d'abord, je note que oui, un type de valeur bloqué dans un dictionnaire immuable est immuable, même s'il s'agit d'un type de valeur mutable. Pourquoi? Parce que les types de valeur ne sont mutés que par mutation de la variable qui les contient. Si votre dictionnaire n'expose pas les variables utilisées pour stocker les types de valeur, les variables ne sont pas modifiées.

Cependant, même si un type de valeur est lui-même immutable un type de valeur immuable peut contenir une référence à un type de référence mutable , et maintenant nous avons le même problème. La limitation du dictionnaire des types de valeurs ne pousse que le problème d'un niveau, il ne le résout pas! Ce que vous avez vraiment besoin de garantir une immuabilité "Deep" est un dictionnaire des types de valeur blustables . Par "blittable", je veux dire un type de valeur sans champs de type de référence. (Considérons par soi-disant parce que vous pouvez sérialiser l'un de ceux-ci au stockage en "blâmant" les bits directement sur le disque.)

Malheureusement, il n'y a pas de contrainte dans le système de type générique pour contraindre à des types de valeur blistables.

Prenons maintenant le problème général des types de référence mutables dans un dictionnaire immuable, que ces types de référence sont là directement ou via un champ de type de valeur. Ce qui peut se tromper si un type de référence est muté hors bande alors qu'il est dans un dictionnaire immuable?

Eh bien, la première chose qui vous vient à l'esprit est qu'un dictionnaire immuable devrait donner la même réponse deux fois à la même question à la même question, et cela n'est plus le cas. Si vous dites «clients [nom] .Address», vous vous attendez à obtenir la même réponse deux fois, mais si le client est un type de référence pouvant être muté, vous obtiendrez une réponse potentiellement différente. Cela pourrait ou pourrait ne pas être souhaitable. (Et note que le dictionnaire donne la même réponse deux fois: il donne la même référence à l'objet client. C'est en fait l'objet client qui ne donne pas la même réponse deux fois.)

En supposant que vous n'essayez pas de mémoialiser les réponses aux questions qui peuvent changer, ce n'est généralement pas un gros problème.

Un problème plus important est quand un objet qui se trouve dans une table de hachage sous forme de mutation de clé, modifiant ainsi sa valeur de hachage et "Perdre" l'objet dans la table.

Si cela se produit, une personne ne garde pas dans les directives. Les lignes directrices sont (1) Les types de référence devraient si possible ne pas baser leurs codes de hachage (et l'égalité) sur des données pouvant être muté et (2) un objet utilisé comme clé dans une table de hachage ne doit pas être muté.


7 commentaires

Y a-t-il un concept de types de types de fichiers incroyables ?NET? Je suppose que vous pouvez en faire un mais au moment de l'exécution, ce n'est pas différent d'un type non incertable? Il existe également de nombreux types de valeur dans .NET qui sont mutables, comme un point similaire, une taille, etc. Savez-vous si vous avez pris cette décision contre les directives ou si l'immuabilité n'était pas une contrepartie des versions antérieures de .net ? Juste curieux parce que cela pourrait même être à cause des raisons de performance, alors je comprends.


@Joan: le temps d'exécution prend en charge parce que les types de pointeur de code dangereux doivent être des pointeurs à des types blittables. Je ne sais pas pourquoi point, etc., sont mutables.


Merci Eric, ne le savait pas.


Si le temps d'exécution est en train de se soucier, ne serait-il pas utile de pouvoir définir un type comme fiable, ce qui signifie que c'est une structure qui ne contient que d'autres types blittables?


(Cela ferait également une sérialisement efficace un problème beaucoup plus facile à résoudre pour ce sous-ensemble de types)


Il convient parfaitement à un objet immuable pour contenir des références à des objets mutables si l'objectif de ces références est d'encapsuler uniquement des aspects immuables d'eux (notamment leur identité). Par exemple, si un atelier de réparation a conservé une liste immuable des Vins des voitures, elle a permis une journée donnée, une telle liste pourrait être utilisée pour déterminer la marque et le modèle de la cinquième voiture que la boutique desservie ce jour-là (depuis la fabrication et le modèle d'une voiture ne peut jamais changer une fois que cela quitte l'usine). Il pourrait également être utilisé par le magasin pour déterminer s'il voit à nouveau la même voiture. Ça ne pouvait pas ...


... Soyez utilisé pour déterminer si la cinquième voiture était rouge ou bleue au moment de la dernière visite. Même si on pouvait trouver cette cinquième voiture compte tenu de son Vin et qu'il voit qu'il est maintenant rouge, et même si l'usine pourrait signaler que la voiture était rouge quand elle était fabriquée, il n'y aurait aucun moyen de déterminer si la voiture aurait pu peindre Bleu avant la dernière visite du service et peint en rouge après. Néanmoins, le fait que de nombreux aspects d'une voiture soient mutables ne signifie pas qu'une liste immuable des voitures ne doit pas être considérée comme "vraiment immuable".



0
votes

Pour comprendre ce qui se passe, déposez-vous à un type plus simple qu'un dictionnaire: une liste . Si on crée une liste , jette quelques éléments dedans, puis crée le transmet au constructeur de Readonlycollection et détruit toutes les références à cette liste autre que Celui contenu dans le loadonlycollection , alors cette liste sera immuable. Son état ne changera jamais, que ce soit que t mutable ou immuable, classe ou structure. Toute personne qui considérerait une telle liste que possible si t est un type de classe mutable échoue à tort la liste des objets de maintien. Ce n'est pas le cas.

si t est un type de classe, une liste n'est pas Hold Objets - IT Identifie eux. Si une liste est rendue immuable comme décrit ci-dessus, après cinq int Les références de tableau ont été ajoutées, Ensuite, tant que cela existe, il tiendra toujours des références à ces mêmes matrices. Le contenu des tableaux peut changer, mais Les propriétés des objets mentionnés par une liste ne font aucune partie de l'état de la liste .

L'état d'un Dictionnaire est un peu plus difficile à définir que l'état d'une liste , surtout si on considère les possibilités de Etats embrouillis causés par Wonky gethashcode () implémentations, mais les mêmes principes s'appliquent. Si tkey est un type de classe, les seuls aspects d'une instance tkey qui font partie de l'état du dictionnaire sont la valeur renvoyée par gethascode , et La classe d'équivalence impliquée par son est égale à méthode; Ces deux choses sont censées être immuables. Aucun aspect légitimement mutable d'un tkey ou TVALUE L'objet de la classe doit être considéré comme faisant partie de l'état d'un tdictionnaire .


0 commentaires

2
votes

Regardez les nouvelles collections immuables de BCL: http : //blogs.msdn.com/b/bclteam/archive/2012/12/18/PREVIEW-OF-MUMUTABLE-Collections-Releed-on-nuge.aspx

Ceci est toujours une version de prévisualisation mais Il contient les types suivants:

  • immutablestack
  • immutaculablee
  • immutableliste
  • immutablesHashSet
  • immutatablesTrette
  • immutabledictionner
  • immutatablesAddictionddiction

    Je souhaite que la prochaine version de C # inclut des mots-clés pour spécifier des contraintes d'immutabilité au niveau de la classe (de la même manière que celle suggérée ici ) et un moyen de cloner des objets plus facilement, comme Que peut-on faire dans F # avec le mot-clé avec : xxx


0 commentaires

0
votes

Jetez un coup d'œil à ceci: http://ayende.com/blog/164739/immutable-Collections-Performance Au fait, soyez complètement prudent lorsque vous utilisez Immuthacessionnaire


0 commentaires