C#の自動プロパティでgetとsetの両方が必須の場合、なぜ「get; set;」を指定する必要があるのですか。全然?
エラー:プロパティまたはインデクサーを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をプライベートにします。
読み取り専用プロパティが必要な場合があるため:
public int Foo { get; private set; }
または書き込み専用プロパティ:
public int Foo { private get; set; }
私はこのトピックに関する私の発見を共有すると思いました。
次のようなプロパティのコーディングは、.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#コード
プレーンなフィールドと区別する方法が必要だからです。
また、さまざまなアクセス修飾子があると便利です。
public int MyProperty { get; private set; }
コンパイラは、ゲッターやセッターを生成するか、フィールドを宣言するかを知る必要があります。
まあ、明らかに、フィールドとプロパティを区別する方法が必要です。しかし、必須キーワードは本当に必要なのでしょうか?たとえば、これらの2つの宣言が異なることは明らかです。
public int Foo;
public int Bar { }
それはうまくいくかもしれません。つまり、コンパイラが理解できると思われる構文です。
しかし、その後、空のブロックに意味的な意味がある状況になります。それは不安定なようです。
プロパティにアクセサーがなかった場合、コンパイラーはそれをフィールドからどのように分離しますか?そして、それをフィールドから何が分けるでしょうか?
誰もそれについて言及していないので...自動プロパティを仮想化してオーバーライドすることができます:
public virtual int Property { get; set; }
Get/setがない場合、どのようにオーバーライドされますか? setter ではなくgetter(---)をオーバーライドできることに注意してください。
public override int Property { get { return int.MinValue; } }
また、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に関するその他のおいしいニュースは、公式プレビュービデオ こちら で入手できます。