1

読み取り専用コレクションがリストへの追加/リストからの削除を妨げていることは承知していますが、コレクション内のオブジェクトのプロパティの設定を妨げないのはなぜですか。

 System.Collections.ObjectModel.ReadOnlyCollection<PersonPhoneNumber> ReadOnlyPhoneNumbers = new System.Collections.ObjectModel.ReadOnlyCollection<PersonPhoneNumber>(_PhoneNumbers);
            ReadOnlyPhoneNumbers[0].Number = "01111111111111";

この質問では、_PhoneNumbers が List であり、PersonPhoneNumber クラスのインスタンスが少なくとも 1 つ含まれていると仮定します。

オブジェクトのコレクションを公開し、オブジェクトを読み取り専用にするにはどうすればよいですか? この問題の原因は、WCF データ コントラクトでプライベート コレクションを公開する必要があることにありますが、コレクションにアクセスできるようにしたくありません。

使いたい:

  Person.Mobile = "011111111111111";

それ以外の:

Person.PhoneNumbers.Add(New PersonPhoneNumber{Number= "01111111111111", Type=Mobile});
4

7 に答える 7

3

オブジェクトを読み取り専用にすることはできません。それには、型を変更する必要があります。読み取り専用オブジェクトのリストを本当に提供する必要がある場合は、公開する型ごとにある種の不変ラッパー型を作成する必要があります (または、型を最初から不変にする必要があります)。もちろん、これは別のタイプになります。相互運用する必要がある場合は、かなり複雑になります...

于 2011-03-01T13:05:38.283 に答える
2

どうすれそれを防ぐことができますか?C# でそのようなものを構築するにはどうすればよいでしょうか? クローン作成をサポートしている場合、インデクサー (など) から返されたものをコピーする可能性がありますが、オブジェクトはクローン作成を実行する必要があります。今与えたコードで何が起こると思いますか? 例外をスローする必要がありますか?PersonPhoneNumberもしそうなら、それはクラス自体に変更を加えています。

基本的に、PersonPhoneNumberクラスを不変に変更する必要があるようです。変更可能な方法でビルドする方法が必要な場合は、作成方法を知っているビルダータイプを作成できますPersonPhoneNumber-例:

var ppn = new PersonPhoneNumber.Builder { /* set properties here }.Build();

ただし、かなり単純な型の場合は、適切なコンストラクターを作成する方が簡単です。

于 2011-03-01T13:06:51.760 に答える
1

これはどう:

  1. 読み取り専用プロパティのみを公開する PersonPhoneNumber のインターフェイスを作成します (セッターなし)
  2. PersonPhoneNumber のコレクションの代わりに、IPersonPhoneNumber の読み取り専用コレクションを作成しますが、その中に PersonPhoneNumber アイテムを入れます。

もちろん、これはコードがアイテムを PersonPhoneNumber にキャストすることを妨げませんが、アイテムのプロパティを誤って変更することを防ぎます

于 2012-05-22T13:40:04.090 に答える
0

PersonPhoneNumberはクラスであるため、は任意のオブジェクトReadOnlyCollectionの参照へのアクセスを提供します。PersonPhoneNumberオブジェクトへの参照を持っているので、オブジェクトPersonPhoneNumberで許可されていることは何でもPersonPhoneNumberできます。オブジェクトがから来たという事実ReadOnlyCollectionは関係ありません。

PersonPhoneNumber代わりに構造体を作成することを検討できます。それを行うと、コレクションからインデックス付きオブジェクトを要求すると、フレームワークはそれをボックス化して、(効率のために) 構造体全体をコピーしないようにします。しかし、それを変更しようとすると、「ボックス化解除変換の結果を変更できません」というエラーが表示されます。

ReadOnlyPhoneNumbers[0].Number = "01111111111111";
// Cannot modify the result of an unboxing conversion

ローカル変数に割り当てることができますが、これによりコピーが作成されます。

PersonPhoneNumber ppn = ReadOnlyPhoneNumbers[0].Number;
ppn.Number = "01111111111111";

ppn はコピーです。ReadOnlyCollection のオリジナルは変更されていません。

(もちろん、構造体に変更PersonPhoneNumberする前に、この変更の他の結果を考慮する必要があります。構造体が不適切になる他の理由があるかもしれません。)

于 2016-01-07T09:05:51.230 に答える
0

問題は、オブジェクトが入るときに読み取り専用にすることです。これらのオブジェクトを読み取り専用にするには、値を設定できないある種のプロキシでそれらをラップする必要があります。

Castle の動的プロキシを使用すると、独自の実装の ReadOnlyProxy でオブジェクトをラップできる場合があります。次に、 add メソッドは、コレクションに入ったときにすべてを ReadOnlyProxy でラップする必要があります。

よくない...

于 2011-03-01T13:07:32.377 に答える
0

あなたが何を望むかは、コレクションの問題ではありません。コレクションはアイテムへの参照を保持し、コレクションにアクセスしてこのアイテムを取得します。
挿入する前に、オブジェクトの複製を試みることができます。これは変更を妨げるものではありませんが、元のオブジェクトは保持されます。それ以外の場合は、読み取り専用ラッパーを作成するか、オブジェクトに別の構造を選択する必要があります。

于 2011-03-01T13:07:38.337 に答える
0

あなたはこの記事を見たいと思うかもしれません。

C# ジェネリック レシピ — 読み取り専用コレクションをジェネリックな方法で作成する

あなたが望むのは、 phonenumbers リストを真のプライベートデータメンバーに保ちながら、さまざまなタイプの電話番号の person オブジェクトのセッターとゲッターを介してアクセスを公開することだと思います。人が各タイプの 1 つしか持てない場合、これは問題なく機能します... そうでない場合は、それをメソッドに変更する必要があります。.AddMobile("011111") のように

于 2011-03-01T13:12:02.877 に答える