web-dev-qa-db-ja.com

プライベートセッター付きのプロパティとget-only-property

C#6.0では、get-onlyプロパティを定義する機能が導入されています。

public ICommand AddCommand { get; }

次のような別のプロパティを定義するとき、ReSharperは自動プロパティをget-onlyにすることができます:を提案します。

private List<Screenshot> Screenshots { get; set; }

さらに、ReSharperは、プライベートゲッターを定義するときに何も言いません。

public ICommand AddCommand { get; private set; }

パブリックget-onlyプロパティ(最初のAddCommandなど)、プライベートget-onlyプロパティ(Screenshotsプロパティなど)、およびパブリックプライベートセッタープロパティ(など)の違いは何ですか2番目のAddCommand)?

私のWPFアプリケーションは、パブリックプロパティ(UICommand)にプライベートセッターが含まれているか、セッターがまったく含まれていないかを気にしていないようですが、確かに違いがあるはずですか?

22
SeToY

コマンドをバインドするこの特定のケースでは、それは実際には重要ではありません。

その他の場合、つまり、コンストラクターを介してサービスを注入するクラスがあり、それを(何らかの理由で)公開したい場合は、読み取り専用プロパティを使用することが重要です。

例えば:

_public class MainViewModel 
{
    public INavigationService NavigationService { get; }

    public MainViewModel(INavigationService navigationService) 
    {
        if(navigationService == null)
            throw new ArgumentNullException(navigationServie);

        NavigationService = navigationService;
    }
}
_

これを使用する場合、このクラスの不変条件を保証し、NavigationServicenullになることはないことを保証します。したがって、使用する前にNavigationServiceに対してnullチェックを行う必要はありません。コンストラクターを離れると、変更することはできません(リフレクションを除く)。

あなたが持っている場合は反対側に

_public class MainViewModel 
{
    public INavigationService NavigationService { get; private set; }

    public MainViewModel(INavigationService navigationService) 
    {
        if(navigationService == null)
            throw new ArgumentNullException(navigationServie);

        NavigationService = navigationService;
    }
}
_

次に、_NavigationService = null_を実行するコードを(誤ってまたは経験の浅い開発者が)作成する可能性があります。nullチェックを行わずにアクセスすると、NullReferenceExceptionが取得され、処理されない場合はアプリケーションがクラッシュします。

例に戻ります。ICommand ...の場合、通常はViewModel内のコマンドにアクセスせず、割り当てるだけです(通常、コンストラクターで、または子ビューモデルが変更されて割り当てたいビューモデルのコンテンツが変更された場合)。親のviewmodelコマンドプロパティへのコマンドです)。

リストの場合:

コードでScreenshots = new List<ScreenShot>()またはScreenshots = DisplayScreenshots()を実行せず、コンストラクターで初期化するだけの場合は、同じ理由で読み取り専用にすることをお勧めします。Screenshotsを保証できます。 nullになることはなく、次のようなコードを記述する必要はありません。

_if(Screenshots != null) 
{
    Screenshots.Add(new Screenshot(...));
}
_

または

_if(Screenshot == null) 
{
    Screenshots = new List<Screenshot>();
}

Screenshots.Add(new Screenshot(...));
_

繰り返し、代わりに常に使用します

_Screenshots.Add(new Screenshot(...));
_

これには、必要なコードが少なくて済み、コードが読みやすく、保守しやすいという大きな利点があります。これは、nullチェックを「忘れて」、NullReferenceExceptionのリスクを冒すことはできないためです。

それがそれをクリアしたことを願っています。

12
Tseng

短い答え:

public ICommand AddCommand { get; }

readonlyフィールドによってサポートされ、コンストラクターの実行を超えてC#コードで変更することはできません。

また、プロパティアクセサがないため、コンパイラはバッキングフィールドを直接割り当てるコードを生成します。

一方:

public ICommand AddCommand { get; private set; }

readonly以外のフィールドでバックアップされ、プライベートメンバーにアクセスできる任意のコードでいつでも割り当てることができます。

この場合、コンパイラは通常のプロパティ設定コードを生成します。

外の世界にとって、プライベートセッターはそれが存在しないかのようです。つまり、実際には存在しなかったのと同じです。

21
Paulo Morgado

コンパイラが宿題をした後のプロパティは次のようになります。


1.1。public ICommand AddCommand { get; }

private readonly ICommand <AddCommand>k__BackingField;
public ICommand AddCommand {
    get { return this.<AddCommand>k__BackingField; }
}


2.2。private List<Screenshot> Screenshots { get; set; }

private List<Screenshot> <Screenshots>k__BackingField;
private List<Screenshot> Screenshots { 
    get { return this.<Screenshots>k__BackingField; }
    set { this.<Screenshots>k__BackingField = value; } 
}


3.3。public ICommand AddCommand { get; private set; }

private ICommand <AddCommand>k__BackingField;
public ICommand AddCommand { 
    get { return this.<AddCommand>k__BackingField; } 
    private set { this.<AddCommand>k__BackingField = value; } 
}

つまり、publicget-onlyプロパティはコンストラクターでのみ割り当てることができます (フィールドが読み取り専用であるため)またはこの新しい構文によって:

public ICommand AddCommand { get; } = new MyCommand(); 

しかし、他の読み取り専用フィールドに関しては、このコードはとにかくコンストラクターに入れられるので、大きな違いはありません。

public MyClass1()
{
    this.<AddCommand>k__BackingField = new MyCommand();
}
6
sotonika