在我看来,.NET 极度缺乏安全、不可变的集合类型,尤其是 BCL,但我也没有看到在外部完成太多工作。有没有人有任何指向(最好)生产质量、快速、不可变的 .NET 集合库的指针。快速列表类型是必不可少的。我还没有准备好切换到 F#。
*编辑:搜索者请注意,这很快就会被纳入 BCL: .NET 不可变集合
在我看来,.NET 极度缺乏安全、不可变的集合类型,尤其是 BCL,但我也没有看到在外部完成太多工作。有没有人有任何指向(最好)生产质量、快速、不可变的 .NET 集合库的指针。快速列表类型是必不可少的。我还没有准备好切换到 F#。
*编辑:搜索者请注意,这很快就会被纳入 BCL: .NET 不可变集合
您可能想查看程序Microsoft.FSharp.Collections
集中的命名空间FSharp.Core
。您不必在 F# 中编程即可使用这些类型。
请记住,从 F# 外部使用时,名称会有所不同。例如,Map
F# 中的 被称为FSharpMap
来自 C#。
.NET BCL 团队发布了.NET 4.5的不可变集合预览
我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>
接口契约,标准的 Add/Remove/Delete/Clear 方法被显式实现,但是它们抛出一个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);
}
我不能说它的生产质量,因为我没有彻底测试过它,但到目前为止它似乎工作得很好......
想到C5,但我不确定它有多快。它已经存在多年,并且非常稳定。
此外,List<T>.AsReadOnly()
IMO 的工作做得相当好,但不幸的是,字典或任意ICollection<T>
's 没有等价物。
你可以试试JaredPar 的BclExtras。