web-dev-qa-db-ja.com

セッターとプライベートセッターの省略?

省略されたセッターを持つプロパティとプライベートセッターを持つプロパティの違いは何ですか?

public string Foo { get; private set; }

public string Foo { get; }
38
Fred

C#6では、get;のみのプロパティは、コンストラクタからのみ設定できます。それ以外の場所からは、読み取り専用です。

private set;は、そのクラス内のどこからでも設定できます。

53
Patrick Hofman

クラスの外から、次の構文を使用しても何も変わりません。

public string Foo { get; }

ただし、コンストラクタ内を除き、クラス内でFooを更新することはできません。そのためには、プライベートセッターが必要になります。

public string Foo { get; private set; }
10
Thomas Ayoub

違いは、生成されたコードが2番目のケースで読み取り専用フィールドを生成し、明らかにプロパティにセッターがないことです。

実際の例を見てみましょう:

public class Test
{
    public Test(string name) { Name = name; }
    public string Name { get; private set; }
}

コンパイラはこれを次のようにコンパイルします。

public class Test
{
    private string <Name>k__BackingField;
    public Test(string name)
    {
        <Name>k__BackingField = name;
    }
    public string Name
    {
        get { return <Name>k__BackingField; }
        private set { <Name>k__BackingField = value; }
    }
}

ご覧のとおり、コンパイラーは自動的にコードを書き換えて、プロパティのバッキングフィールドを設定しています。フィールド名はその不可解な名前になります。これは正当な.NETですが、C#ではありません。つまり、そのような自動生成されたメンバーと競合するC#コードを書くことはできません。

基本的に、C#の自動プロパティは、バッキングフィールドを持つプロパティの構文糖衣であり、コンパイルされる実際のプロパティにはバッキングフィールドがまだあるため、明示的に記述する必要はありません。

ご覧のとおり、フィールドに直接書き込むようにコンストラクターを自動的に書き直しました。とにかくカスタムコードが間に入る可能性がないため、これはプロパティが書き込まれるこのクラス内のすべての場所で行われることに注意してください。

次に、プロパティからセッターを削除して、何が起こるかを見てみましょう。

public class Test
{
    private readonly string <Name>k__BackingField;
    public Test(string name)
    {
        <Name>k__BackingField = name;
    }
    public string Name
    {
        get { return <Name>k__BackingField; }
    }
}

これでフィールドが読み取り専用になりました。また、明らかに、setterもプロパティから削除されています。

したがって、これは実際にはtrue読み取り専用プロパティを使用して単純な型を作成する最良の方法です。プロパティ自体が書き込み不可であるだけでなく、バ​​ッキングフィールドも読み取り専用であるため、簡単に書き込むことができます。 不変タイプ

6

privateセッターは、クラスの内部からのみ使用できるプライベートsetメソッドです。

省略セッターはプロパティをreadonlyにします。したがって、このプロパティの値を設定できるのは、コンストラクタで、または静的な初期化を介してのみです。

4
René Vogt

セッターが省略されたプロパティは、クラスコンストラクターを除くすべての場所(クラス内を含む)でのみ読み取られます。

プライベートセッターを持つプロパティは、外部からのみ(サブクラスに対しても)読み取られますが、内部で書き込み可能です。

3
ChrisF