6
votes

Quelle est la meilleure façon de représenter une liste immuable dans .net?

J'ai récemment commencé à utiliser F # pour "travail réel" et a redécouvert la beauté des structures de données immuables telles que les syndicats discriminés et les enregistrements de F #. Je les ai également trouvés d'être assez droit à utiliser de C #, d'autant plus qu'elles ne nécessitent aucune dépendance directe sur le temps d'exécution F #. Cependant, lorsqu'il s'agit de représenter des listes dans ces structures, je n'ai pas encore trouvé de solution idéale.

Ma première tentative consistait à taper les listes comme SEQ <'A> (iEnumerable dans le monde C #) qui fournit une belle interface de collecte générale sans exporter aucune méthode de mutation de la collection comme icollection <> et ses amis. Cependant, étant donné que je n'ai aucun contrôle sur le constructeur d'une union ou d'enregistrement discriminé, il est possible que le créateur d'une instance de ces types fournisse une implémentation iEnumerable <> pouvant changer ou jeter lorsqu'il est utilisé (tel qu'une expression LINQ). . IEnumerable <> sera-t-il ne me donnera aucune aide du compilateur à prouver que la valeur est immuable et que le fil est en sécurité.

Ma stratégie actuelle consiste à utiliser le type de liste F # qui garantit une collection immuable, mais ajoute une dépendance sur le temps d'exécution F # et semble un peu désactivé lorsqu'il est utilisé à partir de projets non F #. Il permettant cependant que la correspondance de motif F #, que Inumérable <> ne le fait pas. Il ne donne pas non plus à aucun choix dans la représentation réelle d'une liste et, dans certains cas (telles que les grandes listes de valeurs primitives), la représentation de liste F # ne correspond pas vraiment.

Ce que je voudrais vraiment voir est un type de matrice immuable dans .NET, représenté aussi compact que le tableau normal mais avec une garantie de compilateur de ne pas être muté. J'accueillerais Const comme chez C ++, bien que ce ne soit probablement pas très susceptible de se produire. En attendant, y a-t-il une autre option que j'ai manquée?


3 commentaires

Même les listes F # ne sont vraiment vraiment inexistablement immuables, vous pouvez les muterez en place à l'aide de la réflexion (voir FR. wikibooks.org/wiki/f_sharp_programmer/reflection );)


Voir aussi Stackoverflow.com/questions/3485262/ ...


J'aimerais aussi un type de matrice immuable efficace de temps et spatial; Nous sommes Considérant faire le travail de langue et d'exécution pour que cela se produise dans une version hypothétique une version future de C #, mais malheureusement, cela ne va probablement pas finir au milieu du milieu de la liste prioritaire. (N'oubliez pas que toutes les références d'Eric sur les caractéristiques fictives sans budgets mis en œuvre dans des produits non annoncés sont à des fins de divertissement uniquement.)


4 Réponses :


8
votes

Si ce que vous voulez est une implémentation de tableau immuable, vous pouvez simplement utiliser quelque chose comme le suivant

public sealed class ImmutableArray<T> : IEnumerable<T>{
  private readonly T[] m_array;
  public T this[int index] {
    get { return m_array[index]; }
  }
  public int Length {
    get { return m_array.Length; }
  }
  public ImmutableArray(IEnumerable<T> enumerable) {
    m_array = enumerable.ToArray();
  }
  // IEnumerable<T> implementation ommitted
}


1 commentaires

Cela pourrait en effet être le meilleur moyen. Le constructeur devrait copier le tableau mais au moins vous pouvez transmettre librement une instance de ce type et sachez que cela ne changerait pas son contenu.



2
votes

enveloppez votre tableau normal dans un Readonlycollection instance: xxx

(note, cela ne copie pas la collection sous-jacente, mais contient une référence et et modifier des éléments de ilist etc. sont mis en œuvre pour lancer une exception.)


2 commentaires

Je devrais taper staticieusement les propriétés telles que READONLYCollection <>, ce qui est possible, mais n'offre aucun avantage sur le taper comme IEnumerable <>, car le créateur pourrait toujours fournir une collection non mutable. Readonlycollection <> implémente également un certain nombre d'interfaces qu'une collection immuable ne doit pas prendre en charge.


Le problème avec loadonlycollection n'est-ce pas immuable, c'est juste en lecture seule.



1
votes

Je recommanderais de regarder Série d'Eric Lippert's sur immutabilité , c'est une lecture très utile. Partie 4 À propos d'un Queue immuable serait un bon endroit pour commencer.


2 commentaires

Le problème est que ma mise en œuvre d'une file d'attente immuable n'est pas aussi efficace en tant que tableau. Un tableau de, par exemple, des octets, prend un octet par élément. Une file d'octets prend des dizaines d'octets par élément.


Bien que le blog Erics soit définitivement intéressant, ce que je cherchais vraiment était une structure de données existante à utiliser pour la représentation des listes immuables, et non sur la manière de mettre en œuvre une liste immuable ou l'une des structures de données immuables plus difficiles.