web-dev-qa-db-ja.com

C#自動プロパティ-なぜ「get; set;」と書かなければならないのですか?

C#の自動プロパティでgetとsetの両方が必須の場合、なぜ「get; set;」を指定する必要があるのですか。全然?

44
52d6c6af

エラー:プロパティまたはインデクサーをoutまたはrefパラメーターとして渡すことはできません

{get; set;}を指定しなかった場合、コンパイラはそれがフィールドであるかプロパティであるかを認識しません。コンパイラは同じように「見た目」が同じであるため、これは重要です。例えばプロパティで「InitAnInt」を呼び出すと、エラーが発生します。

class Test
{
    public int n;
    public int i { get; set; }
    public void InitAnInt(out int p)
    {
        p = 100;
    }
    public Test()
    {
        InitAnInt(out n); // This is OK
        InitAnInt(out i); // ERROR: A property or indexer may not be passed 
                          // as an out or ref parameter
    }
}

クラスにパブリックフィールド/変数を作成するべきではありません。取得および設定アクセサーを使用するようにいつ変更する必要があるかわからないため、どのコードを中断するか、特に、 APIに対してプログラムするクライアント。

また、取得と設定に異なるアクセス修飾子を使用することもできます。 {取得する; private set;}は、宣言クラスに対してgetをパブリックにし、setをプライベートにします。

52
Binary Worrier

読み取り専用プロパティが必要な場合があるため:

public int Foo { get; private set; }

または書き込み専用プロパティ:

public int Foo { private get; set; }
64
Brian Genisio

私はこのトピックに関する私の発見を共有すると思いました。

次のようなプロパティのコーディングは、.net 3.0ショートカットコール“ auto-implemented property”です。

public int MyProperty { get; set; }

これにより、タイピングの手間が省けます。プロパティを宣言する長い方法は次のとおりです。

private int myProperty;
public int MyProperty 
{
  get { return myProperty; }
  set { myProperty = value; } 
}

「自動実装プロパティ」を使用すると、コンパイラーはコードを生成して、getと「k_BackingField」を設定します。以下は、Reflectorを使用して逆アセンブルしたコードです。

public int MyProperty
{
    [CompilerGenerated]
    get
    {
        return this.<MyProperty>k__BackingField;
    }
    [CompilerGenerated]
    set
    {
        this.<MyProperty>k__BackingField = value;
    }
}

ILから逆アセンブルされたC#コード

また、セッターとゲッターのメソッドを接続します。

[CompilerGenerated]
public void set_MyProperty(int value)
{
    this.<MyProperty>k__BackingField = value;
}
[CompilerGenerated]
public int get_MyProperty()
{
    return this.<MyProperty>k__BackingField;
}

ILから逆アセンブルされたC#コード

読み取り専用の自動実装プロパティを宣言するときは、セッターをプライベートに設定します。

 public int MyProperty { get; private set; }

すべてのコンパイラは "set"をプライベートとしてフラグを立てます。セッターとゲッターメソッドは同じことを言います。

public int MyProperty
{
    [CompilerGenerated]
    get
    {
        return this.<MyProperty>k__BackingField;
    }
    private [CompilerGenerated]
    set
    {
        this.<MyProperty>k__BackingField = value;
    }
}

ILから逆アセンブルされたC#コード

したがって、フレームワークが両方のgetを必要とする理由がわかりません。そして設定;自動実装プロパティ。提供されていない場合は、setおよびsetterメソッドを記述していなかった可能性があります。しかし、これを困難にするコンパイラレベルの問題があるかもしれません、私は知りません。

読み取り専用プロパティを宣言する長い道のりを見ると、

public int myProperty = 0;
public int MyProperty
{
    get { return myProperty; }
}  

そして、逆アセンブルされたコードを見てください。セッターは全くありません。

public int Test2
{
    get
    {
        return this._test;
    }
}

public int get_Test2()
{
    return this._test;
}

ILから逆アセンブルされたC#コード

17
Ron Todosichuk

プレーンなフィールドと区別する方法が必要だからです。

また、さまざまなアクセス修飾子があると便利です。

public int MyProperty { get; private set; }
16

コンパイラは、ゲッターやセッターを生成するか、フィールドを宣言するかを知る必要があります。

4
Kris

まあ、明らかに、フィールドとプロパティを区別する方法が必要です。しかし、必須キーワードは本当に必要なのでしょうか?たとえば、これらの2つの宣言が異なることは明らかです。

public int Foo;
public int Bar { }

それはうまくいくかもしれません。つまり、コンパイラが理解できると思われる構文です。

しかし、その後、空のブロックに意味的な意味がある状況になります。それは不安定なようです。

2
Robert Rossney

プロパティにアクセサーがなかった場合、コンパイラーはそれをフィールドからどのように分離しますか?そして、それをフィールドから何が分けるでしょうか?

2
Rune Grimstad

誰もそれについて言及していないので...自動プロパティを仮想化してオーバーライドすることができます:

public virtual int Property { get; set; }

Get/setがない場合、どのようにオーバーライドされますか? setter ではなくgetter(---)をオーバーライドできることに注意してください。

public override int Property { get { return int.MinValue; } }
2
Zaid Masud

また、C#6.0(Visual Studio 2015では、バージョンUltimate Previewでこの回答が利用可能になった時点で)以降、真の読み取り専用プロパティを実装できます。

public string Name { get; }
public string Name { get; } = "This won't change even internally";

...パブリックゲッター/プライベートセッターのペアで現在不完全な回避策とは対照的に:

public string Name { get; private set; }

public Constructor() { Name="As initialised"; }
public void Method() { Name="This might be changed internally. By mistake. Or not."; }

上記の例(コンパイル済みでオンラインで実行可能 ここ )。

using System;

public class Propertier {
    public string ReadOnlyPlease { get; private set; }

    public Propertier()  { ReadOnlyPlease="As initialised"; }
    public void Method() { ReadOnlyPlease="This might be changed internally"; }
    public override string ToString() { return String.Format("[{0}]",ReadOnlyPlease); }
}

public class Program {
    static void Main() {
        Propertier p=new Propertier();
        Console.WriteLine(p);

//      p.ReadOnlyPlease="Changing externally!";
//      Console.WriteLine(p);

        // error CS0272: The property or indexer `Propertier.ReadOnlyPlease' cannot be used in this context because the set accessor is inaccessible
        // That's good and intended.

        // But...
        p.Method();
        Console.WriteLine(p);
    }
}

C#6.0に関するその他のおいしいニュースは、公式プレビュービデオ こちら で入手できます。

2
Robert Kopeć