适用于.NET的高效,不可变,可扩展的集合
在我看来,.NET存在极端缺乏安全,不可变的集合类型,特别是BCL,但我也没有看到外面的工作。 有没有人有一个(最好)生产质量,快速,不可变的.NET集合库的任何指针。 快速列表类型是必不可少的。 我还没准备好切换到F#。
*编辑:注意搜索者,很快就会进入BCL: .NET不可变集合
您可能希望查看FSharp.Core
程序FSharp.Core
的Microsoft.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
可以很好地完成IMO的工作,但遗憾的是没有相应的字典或任意ICollection
。
您可以查看Extras或System.collections.concurrent 教程
您可以尝试JaredPar的BclExtras 。