web-dev-qa-db-ja.com

ゲッターのみの自動プロパティを設定できます、なぜですか?

自動プロパティを作成しました:

public int Foo { get; } 

これはゲッターのみです。しかし、コンストラクタを作成するとき、値を変更できます。

public MyClass(string name)
{
    Foo = 5;
}

これは取得専用ですが、なぜそれが可能ですか?

83
Noam B.

これは、この MSDNマガジンの記事「C#:The NewおよびMark MichaelisによるC#6.0 'の改善 および C#6.0ドラフト言語仕様

読み取り専用フィールドのセッターは、コンストラクターでのみアクセス可能です。他のすべてのシナリオでは、フィールドはまだ読み取り専用であり、以前と同様に動作します。

これは、入力する必要のあるコードの量を減らし、値を保持するためにプライベートモジュールレベルの変数を明示的に宣言する必要をなくすための便利な構文です。

C#3の自動実装プロパティの導入により、可変プロパティ(ゲッターとセッターを持つもの)が不変プロパティ(ゲッターのみを持つもの)よりも速く記述されるようになったため、この機能は重要と見なされました。変更可能なプロパティを使用して、通常は読み取り専用プロパティに必要なバッキングフィールドのコードを入力する必要がないようにします。自動実装プロパティの詳細については、Microsoft C#プログラミングガイドの 関連セクション を参照してください。

このブログ投稿「#1,207 – C#6.0 –読み取り専用プロパティ用の自動プロパティ初期化機能」ショーン・セクストン 次のような良い説明と例があります。

C#6.0より前のバージョンでは、読み取り専用(不変)プロパティが必要な場合、通常、コンストラクターで初期化される読み取り専用のバッキングフィールドを使用します(以下を参照)。

public class Dog 
{
    public string Name { get; set; }

    // DogCreationTime is immutable
    private readonly DateTime creTime;
    public DateTime DogCreationTime 
    {
        get { return creTime; }
    }

    public Dog(string name)
    {
        Name = name;
        creTime = DateTime.Now;
    }
}

C#6.0では、自動実装プロパティを使用して読み取り専用プロパティを実装できます。これを行うには、自動プロパティ初期化子を使用します。結果は、バッキングフィールドを明示的に宣言する必要がある上記の例よりもはるかにきれいです。

public class Dog
{
    public string Name { get; set; }

    // DogCreationTime is immutable
    public DateTime DogCreationTime { get; } = DateTime.Now;

    public Dog(string name)
    {
        Name = name;
    }
}

詳細は、GitHubのドットネットRoslynリポジトリ にも記載されています

自動プロパティは、セッターなしで宣言できるようになりました。

ゲッターのみの自動プロパティのバッキングフィールドは、暗黙的に読み取り専用として宣言されます(ただし、これはリフレクションの目的でのみ重要です)。上記の例のように、プロパティの初期化子を使用して初期化できます。また、ゲッターのみのプロパティを宣言型のコンストラクター本体に割り当てることができます。これにより、基になるフィールドに値が直接割り当てられます。

これは型をより簡潔に表現することに関するものですが、可変型と不変型の間の言語の重要な違いも取り除くことに注意してください:auto-propertiesは、クラスを可変にしたい場合にのみ使用できる速記でした。それは素晴らしかった。現在、ゲッターのみの自動プロパティにより、競技場は可変と不変の間で平準化されています。

および C#6.0ドラフト言語仕様 (注:マイクロソフトに関する限り、言語仕様は最終的なものですが、まだ承認されていない EMCA/ISO規格 、したがって「ドラフト」):

自動実装プロパティ

自動的に実装されるプロパティ(または略して自動プロパティ)は、セミコロンのみのアクセサーボディを持つ非抽象の非外部プロパティです。自動プロパティにはgetアクセサーが必要であり、オプションでsetアクセサーを設定できます。

プロパティが自動的に実装されるプロパティとして指定されると、そのプロパティに対して非表示のバッキングフィールドが自動的に使用可能になり、アクセサが実装されてそのバッキングフィールドの読み取りと書き込みが行われます。自動プロパティにアクセサーが設定されていない場合、バッキングフィールドは読み取り専用(読み取り専用フィールド)と見なされます。読み取り専用フィールドと同様に、ゲッターのみの自動プロパティも、囲んでいるクラスのコンストラクターの本体で割り当てることができます。このような割り当ては、プロパティの読み取り専用バッキングフィールドに直接割り当てられます。

自動プロパティには、任意でproperty_initializerを含めることができます。これは、variable_initializer(変数初期化子)としてバッキングフィールドに直接適用されます。

113
tomRedox

これは C#6の新機能 です。これにより、読み取り専用プロパティを作成し、コンストラクターから値を初期化できます(または宣言時にインラインで)。

このプロパティの値をコンストラクター外で変更しようとすると、コンパイルエラーが発生します。

値を(インラインまたはコンストラクター内で)初期化すると、値を変更できないという意味で、読み取り専用です。

24
Yacoub Massad

コンストラクター(または自動プロパティ初期化子)から読み取り専用プロパティを初期化できない場合、そのタイプのデフォルト値(数値の場合は0、参照タイプの場合はnull)を常に返すため、役に立たない)。同じセマンティクスがすべてのC#バージョンの readonly フィールドに適用されます。

真のゲッターのみのプロパティ(コンストラクターから初期化できない)を定義するには、定義の一部として返すものを指定する必要があります。

public int Foo { get { return 5; } }

または、C#6でより簡潔に:

public int Foo => 5;
16
Douglas

「読み取り専用の自動実装プロパティ」

まず、プロパティが

public string FirstName { get; }

「読み取り専用の自動実装プロパティ」として知られています

これを確認するには、Visual Studioで上記のコードを実行して確認します。言語バージョンをC#6.0からC#​​5.0に変更すると、コンパイラは次の例外をスローします。機能「C#5では読み取り専用の自動実装プロパティ」は使用できません。言語バージョン6以降を使用してください。

c#言語バージョンを変更するには here にアクセスしてください

今、私はあなたの2番目の質問に来ています

「これはゲッターのみです。しかし、コンストラクタを構築するとき、値を変更できます」

マイクロソフトは、読み取り専用のロジックに「読み取り専用の自動実装プロパティ」を導入しています。私たちが知っているように、キーワード「readonly」はC#1.0から利用可能です。 「読み取り専用」キーワードをフィールドの修飾子として使用し、そのフィールドは2つの方法またはで割り当てることができます同じクラスのコンストラクターでの宣言時間または

同じ方法で、「読み取り専用の自動実装プロパティ」の値を2つの方法で割り当てることができます

Way1(宣言時):

public string FirstName { get; } = "Banketeshvar";

Way2(同じクラスのコンストラクター内)

Person()
{
 FirstName  = "Banketeshvar";
}

Purely ReadOnlyプロパティ

あなたが純粋に読み取り専用のプロパティを探しているなら、これに行きます

public string FullName => "Manish Sharma";

コンストラクタから「FullName」プロパティの値を割り当てることができなくなりました。それを行おうとすると、次の例外がスローされます

「プロパティまたはインデクサー「Person.FullName」を割り当てることはできません-読み取り専用です」

自動プロパティ機能は、C#3.0のリリース中に言語に追加されました。バッキングフィールドなしでプロパティを定義できますが、コンストラクタを使用してこれらの自動プロパティをデフォルト以外の値に初期化する必要があります。 C#6.0には、以下のようなコンストラクタなしでこれらのプロパティを初期化できる自動プロパティ初期化機能と呼ばれる新しい機能が導入されています。

以前は、自動プロパティを使用してオブジェクトを作成し、以下のように自動プロパティをデフォルト以外の値に初期化する場合、コンストラクターが必要です。

public class MyClass
{
    public int Foo { get; }

    public Foo(int foo)
    {
        Foo = foo;
    }
}

C#6.0では、自動プロパティで初期化子を使用できるため、明示的なコンストラクターコードは不要です。

public string Foo { get; } = "SomeString";

public List<string> Genres { get; } = new List<string> { "Comedy", "Drama" };

詳細についてはこちらをご覧ください

4
Rahul Nikate

readonlyと宣言された変数はコンストラクター内で記述できますが、属性を尊重する言語では、コンストラクターが戻った後は変更できません。その修飾子は、コンストラクターのパラメーターに基づいて値が変わるフィールド(コンストラクターが開始する前に初期化できないことを意味する)に必要なことが多いが、コンストラクターが戻った後に変更する必要がないため、言語機能として提供されましたフィールドとして公開される変数にのみ使用できます。 readonlyで修飾されたフィールドのセマンティクスは、多くの場合、フィールドではなくプロパティとして、クラス(クラスは不変のものも含む)を公開する方が良いことを除いて、パブリックメンバーに最適です。

クラスが通常のフィールドと同じくらい簡単に可変プロパティを公開できるようにする読み取り/書き込み自動プロパティが存在するように、クラスがreadonly修飾フィールドと同じくらい簡単に不変プロパティを公開できるようにする読み取り専用自動プロパティが存在します。 readonlyで修飾されたフィールドがコンストラクタで記述できるように、get-onlyプロパティでも同様です。

1
supercat