14

在我看来,.NET 极度缺乏安全、不可变的集合类型,尤其是 BCL,但我也没有看到在外部完成太多工作。有没有人有任何指向(最好)生产质量、快速、不可变的 .NET 集合库的指针。快速列表类型是必不可少的。我还没有准备好切换到 F#。

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

4

7 回答 7

19

您可能想查看程序Microsoft.FSharp.Collections集中的命名空间FSharp.Core。您不必在 F# 中编程即可使用这些类型。

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

于 2010-08-14T22:14:29.370 回答
11

.NET BCL 团队发布了.NET 4.5的不可变集合预览

于 2012-12-20T14:47:19.237 回答
9
于 2010-08-14T22:37:59.470 回答
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>接口契约,标准的 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);
    }

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

于 2010-08-14T22:49:25.300 回答
1

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

此外,List<T>.AsReadOnly()IMO 的工作做得相当好,但不幸的是,字典或任意ICollection<T>'s 没有等价物。

于 2010-08-14T22:06:51.977 回答
1

您可以查看ExtrasSystem.collections.concurrent 教程

于 2010-08-14T22:25:07.197 回答
0

你可以试试JaredPar 的BclExtras

于 2010-09-05T17:25:30.267 回答