3

おそらく次の問題をご存知でしょう: 2 つのオブジェクト A と B の間でコレクションを共有したい (または、同様にプロパティによってコレクションを公開したい) と ... まあ、これは実際には良い考えではないことに気付きます。そしてBはコレクションを変更し、何とかハルマゲドンを手に入れることができます...

しかし、コレクション全体を共有するのではなく、コレクションのアイテムを使用してオブジェクトを初期化するか、アイテムをオブジェクトのメソッドに渡したいだけであることに気付くことがよくあります。さらに、オブジェクトのアイテムはオブジェクトの存続期間中に変更されないため、多くの場合、次のようなことを行うことになります。

public class Foo
{
  private List<int> items;

  public Foo(IEnumerable<int> items)
  {
    this.items = items.ToList();
  }

  public ReadOnlyCollection<int> Items
  {
    get { return new ReadOnlyCollection(this.items); }
  }
}

.ToList() と ReadonlyCollection-Wrapper の両方が問題に対する合理的な解決策を提供しますが、いくつかの問題もあります。クライアントはコレクションを変更しませんが、コレクションが変更されないという保証をクライアントに与えません。

実際、私が書くほとんどのクラス (推測: 80 - 90 %) は事実上不変であり、基本的に不変配列を表すコレクションを集約するため、これは私がよく直面する状況です (このコンテキストでは、固定サイズの不変シーケンスを意味します)。アイテムの)。私の見解では、この問題に対する適切な解決策は非常に単純です。コンストラクターで適切に初期化されることが保証されている配列のラッパー クラスを構築し、基になる配列を変更しないメソッド/プロパティのみを提供します。

簡単に言えば、不変配列の概念の次の(自明な)実装に問題はありますか?

ところで:私はシーケンスが適切な名前であると判断しました.a)それは意図を非常によく説明しています(アイテムの固定サイズの不変シーケンス)b).netで現在使用されている名前ではなく、c)それは非常に短いです私はそれを広範囲に使用することを計画しているので重要です。

public sealed class Sequence<T> : IEnumerable<T>
    {
        private readonly T[] items;

        public Sequence(IEnumerable<T> items)
        {
            this.items = items.ToArray();
        }

        public Sequence(int size, Func<int, T> producer)
        {
            this.items = new T[size];

            for (int i = 0; i < size; i++)
            {
                this.items[i] = producer(i);
            }
        }

        public T this[int i]
        {
            get { return this.items[i]; }
        }

        public int Length
        {
            get { return this.items.Length; }
        }

        public bool Contains(T item)
        {
            for (int i = 0; i < this.items.Length; i++)
            {
                if (this.items[i].Equals(item))
                    return true;
            }

            return false;
        }

        public Enumerator<T> GetEnumerator()
        {
            return new Enumerator<T>(this);
        }

        IEnumerator<T> System.Collections.Generic.IEnumerable<T>.GetEnumerator()
        {
            return GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        public struct Enumerator<T> : IEnumerator<T>
        {
            private T[] items;
            private int nextIndex;
            private T current;

            internal Enumerator(Sequence<T> immutableArray)
            {
                this.items = immutableArray.items;
                this.nextIndex = 0;
                this.current = default(T);
            }

            public T Current
            {
                get { return this.current; }
            }

            object System.Collections.IEnumerator.Current
            {
                get { return this.Current; }
            }

            public void Dispose()
            {
            }

            public bool MoveNext()
            {
                if (this.nextIndex < this.items.Length)
                {
                    this.current = this.items[this.nextIndex];
                    this.nextIndex++;
                    return true;
                }
                else
                {
                    return false;
                }
            }

            public void Reset()
            {
                this.nextIndex = 0;
                this.current = default(T);
            }
        }
    }
4

3 に答える 3

3

あなたのSequenceクラスはあなたに何を与えますReadOnlyCollectionか?単純な継承を使用して、必要なコンストラクターを提供することはできませんか?

public class Sequence<T> : ReadOnlyCollection<T>
{
    public Sequence(IEnumerable<T> items)
        : base(items.ToList()) { }

    public Sequence(int size, Func<int, T> generator)
        : base(Enumerable.Range(0, size).Select(generator).ToList()) { }

    // properties, methods etc provided by the ReadOnlyCollection base class
}
于 2009-09-16T13:42:03.160 に答える
2

大丈夫そうです。を使用するか、単に返すだけで、コード全体IEnumerableを数行に圧縮できることに注意してください。yield returnItems.GetEnumerator()

于 2009-09-16T13:34:58.930 に答える
1

.NET は最初の不変コレクションを出荷したばかりなので、試してみることをお勧めします。

于 2012-12-24T17:11:31.153 に答える