5

これは説明するのがちょっと難しいですが、私の英語が十分であることを願っています。

クラス「B」のオブジェクトのリストを維持する必要があるクラス「A」があります(プライベートリストなど)。クラス「A」の消費者は、リストに項目を追加できる必要があります。アイテムがリストに追加された後、消費者はそれらを再度変更することはできませんが、リスト自体を調整 (アイテムの追加または削除) することはできません。しかし、彼はリスト内の項目を列挙し、それらの値を取得できるはずです。そのパターンはありますか?どうやってそれをしますか?

質問が十分に明確でない場合は、お知らせください。

4

8 に答える 8

4

リストまたはそのアイテムを編集できないようにするには、それらをimmutableにする必要があります。つまり、リクエストごとに要素の新しいインスタンスを返す必要があります。

Eric Lippert の優れた一連の「C# における不変性」を参照してください: http://blogs.msdn.com/ericlippert/archive/tags/Immutability/C_2300_/default.aspx (少し下にスクロールする必要があります)

于 2008-09-24T10:34:54.270 に答える
1

これらの回答の多くが示すように、コレクション自体を不変にする方法はたくさんあります。

コレクションのメンバーを不変に保つには、より多くの労力が必要です。1 つの可能性は、ファサード/プロキシを使用することです (簡潔で申し訳ありません)。

class B
{
    public B(int data) 
    { 
        this.data = data; 
    }

    public int data
    {
        get { return privateData; }
        set { privateData = value; }
    }

    private int privateData;
}

class ProxyB
{
    public ProxyB(B b)   
    { 
        actual = b; 
    }

    public int data
    {
        get { return actual.data; }
    }

    private B actual;
}

class A : IEnumerable<ProxyB>
{
    private List<B> bList = new List<B>();

    class ProxyEnumerator : IEnumerator<ProxyB>
    {
        private IEnumerator<B> b_enum;

        public ProxyEnumerator(IEnumerator<B> benum)
        {
            b_enum = benum;
        }

        public bool MoveNext()
        {
            return b_enum.MoveNext();
        }

        public ProxyB Current
        {
            get { return new ProxyB(b_enum.Current); }
        }

        Object IEnumerator.Current
        {
            get { return this.Current; }
        }

        public void Reset()
        {
            b_enum.Reset();
        }

        public void Dispose()
        {
            b_enum.Dispose();
        }
    }

    public void AddB(B b) { bList.Add(b); }

    public IEnumerator<ProxyB> GetEnumerator()
    {
        return new ProxyEnumerator(bList.GetEnumerator());
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

このソリューションの欠点は、呼び出し元が、追加した B オブジェクトではなく、ProxyB オブジェクトのコレクションを反復処理することです。

于 2008-09-24T13:07:09.273 に答える
0

私が考えることができる最も簡単な方法は、編集が許可されなくなった場合に、基になるコレクションの読み取り専用バージョンを返すことです。

public IList ListOfB
{
    get 
    {
        if (_readOnlyMode) 
            return listOfB.AsReadOnly(); // also use ArrayList.ReadOnly(listOfB);
        else
            return listOfB;
    }
}

ただし、個人的には、基になるリストをクライアントに公開せず、Bインスタンスを追加、削除、および列挙するためのメソッドを提供するだけです。

于 2008-09-24T10:48:50.947 に答える
0

基本的に、クラス B の項目への参照を与えることは避けたいと考えています。そのため、アイテムのコピーを作成する必要があります。

これは List オブジェクトの ToArray() メソッドで解決できると思います。変更を防ぎたい場合は、リストのディープ コピーを作成する必要があります。

一般的に言えば、ほとんどの場合、特にコンシューマーも作成する場合は、適切な動作を強制するためにコピーを作成する価値はありません。

于 2008-09-24T10:32:04.263 に答える
0

編集:エディション コンテキストのサポートを追加しました。呼び出し元は、編集コンテキスト内にのみ要素を追加できます。さらに、インスタンスの有効期間中に作成できるエディション コンテキストを 1 つだけにすることもできます。


カプセル化を使用すると、内部のプライベート メンバーにアクセスするための一連のポリシーを定義できます。次の例は、要件の基本的な実装です。

namespace ConsoleApplication2
{
    using System;
    using System.Collections.Generic;
    using System.Collections;

    class B
    {
    }

    interface IEditable
    {
        void StartEdit();
        void StopEdit();
    }

    class EditContext<T> : IDisposable where T : IEditable
    {
        private T parent;

        public EditContext(T parent)
        {
            parent.StartEdit();
            this.parent = parent;
        }

        public void Dispose()
        {
            this.parent.StopEdit();
        }
    }

    class A : IEnumerable<B>, IEditable
    {
        private List<B> _myList = new List<B>();
        private bool editable;

        public void Add(B o)
        {
            if (!editable)
            {
                throw new NotSupportedException();
            }
            _myList.Add(o);
        }

        public EditContext<A> ForEdition()
        {
            return new EditContext<A>(this);
        }

        public IEnumerator<B> GetEnumerator()
        {
            return _myList.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        public void StartEdit()
        {
            this.editable = true;
        }

        public void StopEdit()
        {
            this.editable = false;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            A a = new A();
            using (EditContext<A> edit = a.ForEdition())
            {
                a.Add(new B());
                a.Add(new B());
            }

            foreach (B o in a)
            {
                Console.WriteLine(o.GetType().ToString());
            }

            a.Add(new B());

            Console.ReadLine();
        }
    }
}
于 2008-09-24T10:20:06.240 に答える
0
public class MyList<T> : IEnumerable<T>{

    public MyList(IEnumerable<T> source){
        data.AddRange(source);
    }

    public IEnumerator<T> GetEnumerator(){
        return data.Enumerator();
    }

    private List<T> data = new List<T>();
}

欠点は、消費者が Enumerator から取得した項目を変更できることです。解決策は、プライベート List<T> のディープコピーを作成することです。

于 2008-09-24T10:38:34.527 に答える
0

リストに追加された B インスタンス自体も不変にする必要があるかどうかは明確ではありませんでした。ここで、B に読み取り専用インターフェイスを使用し、これらをリストからのみ公開するというトリックを実行できます。

internal class B : IB
{
    private string someData;

    public string SomeData
    {
        get { return someData; }
        set { someData = value; }
    }
}

public interface IB
{
    string SomeData { get; }
}
于 2008-09-24T10:40:55.363 に答える
0

うわー、ここには単純な問題に対する非常に複雑な答えがいくつかあります。

プライベートを持つList<T>

方法を用意してくださいpublic void AddItem(T item)- それが機能しないようにすると決めたときはいつでも、機能しないようにします。例外をスローするか、サイレントに失敗させることができます。あなたがそこで何をしていたかによります。

するpublic T[] GetItems()メソッドを持っているreturn _theList.ToArray()

于 2008-09-24T11:11:14.510 に答える