在我看来,.NET存在极端缺乏安全,不可变的集合类型,特别是BCL,但我也没有看到外面的工作。有没有人有任何指向(优选)生产质量,快速,不可变的.NET集合库。快速列表类型是必不可少的。我还没准备好切换到F#。
*编辑:请注意搜索者,很快就会进入BCL:.NET immutable collections
答案 0 :(得分:19)
您可能需要查看FSharp.Core
程序集中的Microsoft.FSharp.Collections
命名空间。您不必须使用F#编程才能使用这些类型。
请记住,从F#外部使用时名称会有所不同。例如,F#中的Map
被称为来自C#的FSharpMap
。
答案 1 :(得分:11)
.NET BCL团队为.NET 4.5发布了Immutable Collections preview
答案 2 :(得分:9)
答案 3 :(得分:6)
我前段时间写了一篇ImmutableList<T>
课程:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class ImmutableList<T> : IList<T>, IEquatable<ImmutableList<T>>
{
#region Private data
private readonly IList<T> _items;
private readonly int _hashCode;
#endregion
#region Constructor
public ImmutableList(IEnumerable<T> items)
{
_items = items.ToArray();
_hashCode = ComputeHash();
}
#endregion
#region Public members
public ImmutableList<T> Add(T item)
{
return this
.Append(item)
.AsImmutable();
}
public ImmutableList<T> Remove(T item)
{
return this
.SkipFirst(it => object.Equals(it, item))
.AsImmutable();
}
public ImmutableList<T> Insert(int index, T item)
{
return this
.InsertAt(index, item)
.AsImmutable();
}
public ImmutableList<T> RemoveAt(int index)
{
return this
.SkipAt(index)
.AsImmutable();
}
public ImmutableList<T> 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<T> GetEnumerator()
{
if (_items == null)
return Enumerable.Empty<T>().GetEnumerator();
return _items.GetEnumerator();
}
public bool Equals(ImmutableList<T> other)
{
if (other == null || this._hashCode != other._hashCode)
return false;
return this.SequenceEqual(other);
}
#endregion
#region Explicit interface implementations
void IList<T>.Insert(int index, T item)
{
throw new InvalidOperationException();
}
void IList<T>.RemoveAt(int index)
{
throw new InvalidOperationException();
}
T IList<T>.this[int index]
{
get
{
if (_items == null)
throw new IndexOutOfRangeException();
return _items[index];
}
set
{
throw new InvalidOperationException();
}
}
void ICollection<T>.Add(T item)
{
throw new InvalidOperationException();
}
void ICollection<T>.Clear()
{
throw new InvalidOperationException();
}
bool ICollection<T>.IsReadOnly
{
get { return true; }
}
bool ICollection<T>.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<T>)
{
var other = (ImmutableList<T>)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<T>
接口契约,标准的添加/删除/删除/清除方法是明确实现的,但它们会抛出InvalidOperationException
。
这个类使用了一些非标准的扩展方法,它们是:
public static class ExtensionMethods
{
public static IEnumerable<T> Append<T>(this IEnumerable<T> source, T item)
{
return source.Concat(new[] { item });
}
public static IEnumerable<T> SkipFirst<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
bool skipped = false;
foreach (var item in source)
{
if (!skipped && predicate(item))
{
skipped = true;
continue;
}
yield return item;
}
}
public static IEnumerable<T> SkipAt<T>(this IEnumerable<T> source, int index)
{
return source.Where((it, i) => i != index);
}
public static IEnumerable<T> InsertAt<T>(this IEnumerable<T> 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<T> ReplaceAt<T>(this IEnumerable<T> source, int index, T item)
{
return source.Select((it, i) => i == index ? item : it);
}
}
这是一个帮助类来创建ImmutableList<T>
的实例:
public static class ImmutableList
{
public static ImmutableList<T> CreateFrom<T>(IEnumerable<T> source)
{
return new ImmutableList<T>(source);
}
public static ImmutableList<T> Create<T>(params T[] items)
{
return new ImmutableList<T>(items);
}
public static ImmutableList<T> AsImmutable<T>(this IEnumerable<T> source)
{
return new ImmutableList<T>(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);
}
我不能说它的生产质量,因为我没有彻底测试过,但到目前为止看起来效果还不错......
答案 4 :(得分:1)
此外,List<T>.AsReadOnly()
能够很好地完成IMO的工作,但不幸的是,字典或任意ICollection<T>
没有相应的内容。
答案 5 :(得分:1)
答案 6 :(得分:0)
你可以试试JaredPar的BclExtras。