どっち - c# フォーム サイズ変更 コントロール



不変か不変か? (4)

私が理解しているように、 不変型は本質的にスレッドセーフなので、さまざまな場所で読むことができました。なぜそうであるのか理解していると思います。 オブジェクトが作成された後にインスタンスの内部状態を変更できない場合は、インスタンス自体への同時アクセスに問題はないようです。

したがって、私は次のList作成することができます:

class ImmutableList<T>: IEnumerable<T>
{
    readonly List<T> innerList;

    public ImmutableList(IEnumerable<T> collection)
    {
         this.innerList = new List<T>(collection);
    }

    public ImmutableList()
    {
         this.innerList = new List<T>();
    }

    public ImmutableList<T> Add(T item)
    {
         var list = new ImmutableList<T>(this.innerList);
         list.innerList.Add(item);
         return list;
    }

    public ImmutableList<T> Remove(T item)
    {
         var list = new ImmutableList<T>(this.innerList);
         list.innerList.Remove(item);
         return list;
    } //and so on with relevant List methods...

    public T this[int index]
    {
        get
        {
            return this.innerList[index];
        }
    }

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

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

だから問題は:これは本当に 不変型ですか? それは本当にスレッドセーフですか?

明らかに、型自体は不変ですが、 Tが保証されていないので、ジェネリック型と直接関連する同時アクセスおよびスレッド問題が発生する可能性があります。 これは、 ImmutableList変更可能と見なさなければならないのだろうか?

する必要がありますclass ImmutableList<T>: IEnumerable<T> where T: structは本当に不変であると考えられる唯一の型ですか?

この問題に関するご意見ありがとうございます。

更新 :たくさんの回答/コメントが、私が投稿したImmutableListの特定の実装に集中しています。これはおそらく非常に良い例ではありません。 しかし、問題の問題は、実装ではありません。 私が尋ねる質問は、 ImmutableList<MutableT>が本当に不変型であり、不変型が伴うすべてを考慮している場合です。

https://ffff65535.com


オブジェクトが作成された後にインスタンスの内部状態を変更できない場合は、インスタンス自体への同時アクセスに問題はないようです。

これは一般的なケースです。

これは本当に不変型ですか?

簡単にまとめると、変更可能リストの周りにコピー・オン・ライト・ラッパーがあります。 不変のリストに新しいメンバを追加してもリストは変更されません。 その代わりに、基本となる変更可能リストのコピーを作成し、コピーに追加して、コピーの周りにラッパーを返します。

ラッピングしている基になるリストオブジェクトが読み込まれたときに内部状態を変更しない限り、元の "不変"の定義を満たしています。

私はこれが不変のリストを実装する非常に効率的な方法ではないことに注意してください。 たとえば、不変のバランスのとれたバイナリツリーを使うと、よりうまくいくでしょう。 あなたのスケッチは、あなたが新しいリストを作るたびに時間とメモリの両方でO(n)です。 それほど難なくO(log n)に改善することができます。

それは本当にスレッドセーフですか?

提供される可変リストは複数の読者にとってスレッドセーフです。

これはあなたにとって興味深いかもしれません:

http://blogs.msdn.com/b/ericlippert/archive/2011/05/23/read-only-and-threadsafe-are-different.aspx

明らかに、型自体は不変ですが、Tが保証されていないので、ジェネリック型と直接関連する同時アクセスおよびスレッド問題が発生する可能性があります。 それは、 ImmutableList<T>が可変であると考えられるべきであるということですか?

それは技術的な問題ではなく、哲学的な質問です。 人の名前の不変のリストを持っていて、リストが決して変更されないが、人のひとりが死んだ場合、名前のリストは "変更可能"ですか? 私はそう思わないだろう。

リストに関する質問に常に同じ回答がある場合、リストは不変です。 人々の名前のリストには、「リストには何人の名前がありますか?」 リストに関する質問です。 「どれくらいの人が生きているの?」 リストに関する質問ではありません、それはリストによって参照される人々に関する質問です。 その質問に対する答えは時間とともに変化します。 最初の質問に対する答えはありません。

する必要があります。クラスImmutableList<T>: IEnumerable<T> where T: structは真に不変であると考えられる唯一の型ですか?

私はあなたに従っていない。 Tを構造体にすることを何に変更するのですか? OK、Tは構造体に制限されています。 私は不変の構造体を作る:

struct S
{
    public int[] MutableArray { get; private set; }
    ...
}

そして今、私はImmutableList<S>ます。 何がSのインスタンスに格納されている可変配列を変更するのを止めますか? リストが不変であり、構造体が不変であるため配列が不変にならないからです。


あなたのコードを使用して、私はこれを行うと言う:

ImmutableList<int> mylist = new ImmutableList<int>();

mylist.Add(1); 

...あなたのコードは、に掲載され、-Exceptionを引き起こします。 スレッドセーブコレクションを作成したり、コレクションをコピーしたり(少なくとも試してみると)、スレッドをセーブすることができます。

Eric Lippertは読書の価値があるかもしれないリンクを掲示しました。


変更可能なオブジェクトの不変なリストとして動作するデータ型の主要な例:MulticastDelegate。 MulticastDelegateは、(オブジェクト、メソッド)のペアの不変のリストとしてかなり正確にモデル化できます。 メソッドのセットと、それらが動作するオブジェクトのアイデンティティは不変ですが、大多数の場合、オブジェクト自体は変更可能です。 実際、多くの場合ではないにしても、多くの場合、デリゲートの目的は、それが参照するオブジェクトを変更することです。

デリゲートがターゲットオブジェクトに対して呼び出すメソッドがスレッドセーフではないかどうかを知ることは、デリゲートの責任ではありません。 代理人は、関数とオブジェクトのアイデンティティのリストが不変であることを保証するだけであり、誰もそれを期待しているとは思わない。

ImmutableList<T>は、同様に常にT型の同じインスタンスのセットを保持する必要があります。 これらのインスタンスのプロパティは変更される可能性がありますが、そのアイデンティティは変更されません。 List<Car>が2つのフォード(シリアル#1234と#4422)を持って作成されていて、両方とも赤で、フォードの1つが青で塗られていた場合、2台の赤い車のリストが青い車と赤い車を持っているリストだが、まだ#1234と#4422を保持するだろう。


要素が変更可能な場合は、データ状態の完全なスナップショットを表していないため、汎用リストは不変ではないと言います。

あなたの例で不変性を達成するには、リスト要素の深いコピーを作成する必要があります。これは毎回効率的ではありません。

あなたはIOGライブラリでこの問題に対する私の解決策を見ることができます





immutability