14

.NET、特にBCLの安全で不変のコレクションタイプが極端に不足しているように見えますが、外部でも多くの作業が行われているのを見たことがありません。.NET用の(できれば)本番品質の高速で不変のコレクションライブラリへのポインタを持っている人はいますか?ファストリストタイプは不可欠です。F#に切り替える準備はまだできていません。

*編集:検索者への注意、これはまもなくBCLに組み込まれます: .NET不変コレクション

4

7 に答える 7

19

アセンブリMicrosoft.FSharp.Collections内の名前空間を確認することをお勧めします。これらのタイプを利用するためにF#でプログラムする必要はありFSharp.Coreません。

F#の外部から使用すると、名前が異なることに注意してください。たとえば、F#のinはC#からMapとして知られています。FSharpMap

于 2010-08-14T22:14:29.370 に答える
11

.NET BCLチームは、.NET4.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>の辞書に相当するものはありません。

于 2010-08-14T22:06:51.977 に答える
1

ExtrasまたはSystem.collections.concurrent チュートリアルをご覧ください。

于 2010-08-14T22:25:07.197 に答える
0

JaredParのBclExtrasを試すことができます。

于 2010-09-05T17:25:30.267 に答える