web-dev-qa-db-ja.com

C#は、getから読み取り専用として変数を返します。セットする;

私はこれの例を見たことがあると誓いますが、少しグーグルしていて、それを見つけることができません。

オブジェクトへの参照を持つクラスがあり、GETが必要です。それのための方法。私の問題は、だれにもそれをいじることができないようにすることです。つまり、読み取り専用バージョンを取得してもらいたいのです(クラス内から変更できるようにする必要があることに注意してください)。

ありがとう

35
Jon

いいえ、これを行う方法はありません。たとえば、List<string>を返す場合(そしてそれは不変ではありません)、呼び出し元エントリを追加できます。

これを回避する通常の方法は、不変のラッパーを返すことです。 ReadOnlyCollection<T>

他の可変タイプの場合、値を返す前に値のクローンを作成する必要がある場合があります。

不変のインターフェイスビューを返すだけでは(たとえば、IEnumerable<T>の代わりにList<T>を返す)、呼び出し元が可変タイプにキャストバックして変更するのを停止しないことに注意してください。

編集:他のものとは別に、この種の懸念は、不変型がコードについて推論しやすくする理由の1つであることに注意してください:)

53
Jon Skeet

削除されたインターフェイスへの参照を返します。

 interface IFoo
   string Bar { get; }

 class ClassWithGet
   public IFoo GetFoo(...);
6
Anton Gogolev

これは不可能です。アクセサを参照型に取得および設定すると、オブジェクトへの参照が取得および設定されます。プライベート(または内部)セッターを使用して参照の変更を防ぐことはできますが、オブジェクトがゲッターによって公開されている場合は、オブジェクト自体の変更を防ぐことはできません。

3
Jamie Ide

オブジェクトがそれほど複雑/広範でない場合は、その周りにラッパーを記述します。

例えば:

class A {
    public string strField = 'string';
    public int intField = 10;
}

class AWrapper {
    private A _aObj;

    public AWrapper(A aobj) {
      _aObj = A;
    }

    public string strField {
         get {
            return _aObj.strField;
         }
    }

    public int intField {
         get {
            return _aObj.intField;
         }
    }
}

これで、クライアントコードにAWrapperクラスのインスタンスを指定するだけで、クライアントはユーザーに表示を許可したものだけを使用できるようになります。

これは少し複雑になり、基本クラスが石に設定されていない場合はうまくスケーリングできない可能性がありますが、ほとんどの単純な状況では、それでうまくいく可能性があります。これはファサードパターンと呼ばれていると思います(ただし、それについては引用しないでください=))

3
justlost

あなたの質問はあなたが探しているように読めます:

public PropertyName { get; private set; }

しかし、これまでの回答を考えると、あなたの質問を正しく解釈しているのかわかりません。それに、ジョン・スキートに質問するのは誰ですか? :)

2
Matt

私はある意味でこの問題に直面しました。私はCategoryViewModelクラスを持っています。これには、プライベートな読み取り専用が必要なプロパティCategoryがあります。

public CategoryViewModel
{
    private Category { get; }

}

実際、他のクラスに読み取り専用としてエクスポートしたいと思います。しかし、私はそのようなことはできません。私の場合(多分それは他の人を助けるでしょう)、私はそれをリポジトリに追加したいと思います。私が見つけた唯一の方法は、リポジトリをパラメータ1として、アクションをパラメータ2として持つ関数を持つことです。

public void ApplyAction(ICategoryRepository repo, Action<ICategoryRepository, Category> action)
{
    action(repo, Category);
}

そのように、他の場所から、私はそのようなことをすることができます:

 categoryViewModel.ApplyAction(_repository, (r, c) => r.MarkForInsertOrUpdate(c));

これは、他の人が特定の場合にのみプロパティを公開し、それらを管理するのに役立ちます。

0
cdie

readOnlyCollectionに同意します

私の簡単なコードを参照してください:

 private List<Device> _devices;
public readonly System.Collections.ObjectModel.ReadOnlyCollection<Device> Devices 
{
 get
 { 
return (_devices.AsReadOnly());
 } 

}

ReadOnlyCollectionにはAddメソッドがないため、ユーザーはプロパティを追加できません。ただし、ユーザーがメソッドを呼び出してオブジェクトを変更できるかどうかは保証されません。

0
pingsft