适用于.NET的高效,不可变,可扩展的集合

在我看来,.NET存在极端缺乏安全,不可变的集合类型,特别是BCL,但我也没有看到外面的工作。 有没有人有一个(最好)生产质量,快速,不可变的.NET集合库的任何指针。 快速列表类型是必不可少的。 我还没准备好切换到F#。

*编辑:注意搜索者,很快就会进入BCL: .NET不可变集合

您可能希望查看FSharp.Core程序FSharp.CoreMicrosoft.FSharp.Collections命名空间。 您不必使用F#编程来使用这些类型。

请记住,从F#外部使用时名称会有所不同。 例如,F#中的Map被称为来自C#的FSharpMap

.NET BCL团队发布了.NET 4.5的Immutable Collections预览版

  • Alexey Romanov的 function性网络
  • Sandro Magi的 Sasa
  • 托尼莫里斯的 Kinet

我不久前写了一个ImmutableList类:

 using System; using System.Collections; using System.Collections.Generic; using System.Linq; public class ImmutableList : IList, IEquatable> { #region Private data private readonly IList _items; private readonly int _hashCode; #endregion #region Constructor public ImmutableList(IEnumerable items) { _items = items.ToArray(); _hashCode = ComputeHash(); } #endregion #region Public members public ImmutableList Add(T item) { return this .Append(item) .AsImmutable(); } public ImmutableList Remove(T item) { return this .SkipFirst(it => object.Equals(it, item)) .AsImmutable(); } public ImmutableList Insert(int index, T item) { return this .InsertAt(index, item) .AsImmutable(); } public ImmutableList RemoveAt(int index) { return this .SkipAt(index) .AsImmutable(); } public ImmutableList Replace(int index, T item) { return this .ReplaceAt(index, item) .AsImmutable(); } #endregion #region Interface implementations public int IndexOf(T item) { if (_items == null) return -1; return _items.IndexOf(item); } public bool Contains(T item) { if (_items == null) return false; return _items.Contains(item); } public void CopyTo(T[] array, int arrayIndex) { if (_items == null) return; _items.CopyTo(array, arrayIndex); } public int Count { get { if (_items == null) return 0; return _items.Count; } } public IEnumerator GetEnumerator() { if (_items == null) return Enumerable.Empty().GetEnumerator(); return _items.GetEnumerator(); } public bool Equals(ImmutableList other) { if (other == null || this._hashCode != other._hashCode) return false; return this.SequenceEqual(other); } #endregion #region Explicit interface implementations void IList.Insert(int index, T item) { throw new InvalidOperationException(); } void IList.RemoveAt(int index) { throw new InvalidOperationException(); } T IList.this[int index] { get { if (_items == null) throw new IndexOutOfRangeException(); return _items[index]; } set { throw new InvalidOperationException(); } } void ICollection.Add(T item) { throw new InvalidOperationException(); } void ICollection.Clear() { throw new InvalidOperationException(); } bool ICollection.IsReadOnly { get { return true; } } bool ICollection.Remove(T item) { throw new InvalidOperationException(); } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } #endregion #region Overrides public override bool Equals(object obj) { if (obj is ImmutableList) { var other = (ImmutableList)obj; return this.Equals(other); } return false; } public override int GetHashCode() { return _hashCode; } #endregion #region Private methods private int ComputeHash() { if (_items == null) return 0; return _items .Aggregate( 983, (hash, item) => item != null ? 457 * hash ^ item.GetHashCode() : hash); } #endregion } 

修改集合的所有方法都返回修改后的副本。 为了满足IList接口契约,标准的Add / Remove / Delete / Clear方法是显式实现的,但它们会抛出InvalidOperationException

这个类使用了一些非标准的扩展方法,它们是:

 public static class ExtensionMethods { public static IEnumerable Append(this IEnumerable source, T item) { return source.Concat(new[] { item }); } public static IEnumerable SkipFirst(this IEnumerable source, Func predicate) { bool skipped = false; foreach (var item in source) { if (!skipped && predicate(item)) { skipped = true; continue; } yield return item; } } public static IEnumerable SkipAt(this IEnumerable source, int index) { return source.Where((it, i) => i != index); } public static IEnumerable InsertAt(this IEnumerable source, int index, T item) { int i = 0; foreach (var it in source) { if (i++ == index) yield return item; yield return it; } } public static IEnumerable ReplaceAt(this IEnumerable source, int index, T item) { return source.Select((it, i) => i == index ? item : it); } } 

这里是一个帮助类来创建ImmutableList实例:

 public static class ImmutableList { public static ImmutableList CreateFrom(IEnumerable source) { return new ImmutableList(source); } public static ImmutableList Create(params T[] items) { return new ImmutableList(items); } public static ImmutableList AsImmutable(this IEnumerable source) { return new ImmutableList(source); } } 

这是一个用法示例:

  [Test] public void Test_ImmutableList() { var expected = ImmutableList.Create("zoo", "bar", "foo"); var input = ImmutableList.Create("foo", "bar", "baz"); var inputSave = input.AsImmutable(); var actual = input .Add("foo") .RemoveAt(0) .Replace(0, "zoo") .Insert(1, "bar") .Remove("baz"); Assert.AreEqual(inputSave, input, "Input collection was modified"); Assert.AreEqual(expected, actual); } 

我不能说它的生产质量,因为我没有彻底测试它,但到目前为止似乎工作得很好……

C5让人想起,但我不确定它有多快。 它已存在多年,并且非常稳定。

另外, List.AsReadOnly()可以很好地完成IMO的工作,但遗憾的是没有相应的字典或任意ICollection

您可以查看Extras或System.collections.concurrent 教程

您可以尝试JaredPar的BclExtras 。