Каков наилучший способ представления неизменяемого списка в .NET? - PullRequest
5 голосов
/ 31 августа 2010

Я недавно начал использовать F # для «реальной работы» и заново открыл красоту неизменных структур данных, таких как различимые объединения и записи в F #. Я также обнаружил, что их довольно просто использовать в C #, тем более что они не требуют каких-либо прямых зависимостей от времени выполнения F #. Однако когда дело доходит до представления списков в этих структурах, я еще не нашел идеального решения.

Моей первой попыткой было напечатать списки как seq <'a> (IEnumerable в мире C #), который обеспечивает хороший общий интерфейс коллекции без экспорта каких-либо методов для изменения коллекции, как это делает ICollection <> и ее друзья. Однако, поскольку я не имею никакого контроля над конструктором различенного объединения или записи, создатель экземпляра этих типов может предоставить реализацию IEnumerable <>, которая может измениться или выбросить при использовании (например, выражение LINQ) , Поэтому IEnumerable <> не окажет мне никакой помощи от компилятора в доказательстве того, что значение является неизменным и поэтому безопасно для потоков.

Моя текущая стратегия состоит в том, чтобы использовать тип списка F #, который гарантирует неизменную коллекцию, но добавляет зависимость от среды выполнения F # и выглядит немного странно при использовании из не F # проектов. Однако он допускает сопоставление с шаблоном F #, которое IEnumerable <> не делает. Это также не дает никакого выбора в реальном представлении списка, и в некоторых случаях (например, большие списки примитивных значений) представление списка F # не очень подходит.

Что я действительно хотел бы увидеть, так это неизменяемый тип массива в .NET, представленный так же компактно, как и обычный массив, но с гарантией компилятора не быть измененным. Я бы приветствовал const, как в C ++, хотя, вероятно, это не очень вероятно. Между тем, есть ли другой вариант, который я пропустил?

Ответы [ 4 ]

7 голосов
/ 31 августа 2010

Если вам нужна реализация неизменяемого массива, вы можете просто использовать что-то вроде следующего

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
}
2 голосов
/ 31 августа 2010

Оберните ваш обычный массив в ReadOnlyCollection<T> экземпляр:

var readOnlyData = new ReadOnlyCollection<TheType>(theRealCollection);

(Обратите внимание, что это не копирует базовую коллекцию, но содержит ссылку и изменяющие элементы IList<T> и т. Д. Реализованы, чтобы вызвать исключение.)

1 голос
/ 12 октября 2013

Microsoft выпускает стабильную версию неизменных коллекций пакет слепков Он пока не поставляется с ImmutableArray . Но эти неизменные структуры данных должны быть очень полезны.

  • ImmutableList
  • ImmutableDictionary
  • ImmutableSortedDictionary
  • ImmutableHashSet
  • ImmutableSortedSet
  • ImmutableStack
  • ImmutableQueue

http://blogs.msdn.com/b/dotnet/archive/2013/09/25/immutable-collections-ready-for-prime-time.aspx

1 голос
/ 01 сентября 2010

Я бы порекомендовал посмотреть серию Эрика Липперта о неизменяемости , это очень полезное чтение.Часть 4 о неизменной очереди будет хорошим началом.

...