web-dev-qa-db-ja.com

ゲッターのみの自動プロパティと式本体のプロパティの違いは何ですか?

C#6では、ゲッターのみの自動プロパティを使用して、プロパティの実装を簡素化できます。たとえば、抽象Streamクラスを実装していた場合:

public override bool CanRead { get; } = true;

ただし、C#6の新機能である式の本文を使用して記述することもできます。

public override bool CanRead => true;

2つの違いは何ですか?どちらを使用する必要がありますか?

56
vcsjones

それらは2つの異なるものの構文糖衣です。前者はバッキングフィールドを初期化し、フィールドの初期化中に割り当ての右側の式に設定します。後者は、式の内容を正確に実行するgetを作成します。

public override bool CanRead { get; } = true;

に相当

private readonly bool __backingFieldCanRead = true;

public override bool CanRead
{
    get
    {
        return __backingFieldCanRead;
    }
}

この

public override bool CanRead => true;

に相当

public override bool CanRead
{
    get
    {
        return true;
    }
}

それらは異なった振る舞いをします。最初のケースは、オブジェクトが作成されてフィールドが初期化されるときにプロパティの値を設定し、もう1つのケースは、プロパティのゲッターが呼び出されるたびに式を評価します。ブールの単純なケースでは、動作は同じです。ただし、その表現が副作用を引き起こす場合は、状況が異なります。この例を考えてみましょう。

class Program
{
    static void Main(string[] args)
    {
        var fooBar1 = new FooBar();
        Console.WriteLine(fooBar1.Baz);
        Console.WriteLine(fooBar1.Baz);
        var fooBar2 = new FooBar();
        Console.WriteLine(fooBar2.Baz);
        Console.WriteLine(fooBar2.Baz);
    }
}

public class FooBar
{
    private static int counter;
    public int Baz => counter++;
}

ここでは、「0、1、2、3」が印刷されています。 static counterフィールドは、プロパティのゲッターが呼び出されるたびに増分されます。ただし、プロパティ初期化子を使用すると、次のようになります。

public int Baz { get; } = counter++;

次に、式がオブジェクトのコンストラクターで評価されるため、「0、0、1、1」が出力されます。

63
vcsjones

私たちの例で説明する場合、私は以前は次のことを好みました。

public override bool CanRead { get; } = true;

しかし、今日、この実装によってバッキングフィールドにメモリが割り当てられることを通知しました。したがって、この実装:bool CanRead => true;4バイト節約できます。

3
Orace