こんにちは!
なかむぅです。
C#でコードを書いていると
とわからなくなり、調べているうちに
といった、そもそもの疑問に至ってしまったので調べてみました。
私が働く会社では、一緒に働いてくれるエンジニアを募集しています♪
- 未経験、第二新卒歓迎
- 学歴・転職回数・離職期間不問
- 残業は月15時間以下で残業代は全額支給
- 経験者は月給23万円以上
- 年収100万以上UP↑↑↑も可能
- 長く働いていても年収が全然上がらないから、一気に年収を上げたい
- 残業をしたくてしているわけではないので、残業代はしっかりと出して欲しい
- やりたいことに挑戦させてもらえないから、自分がしてみたいことに挑戦したい
- 通勤時間が長すぎるから、できるだけ短くしたい
- もっと勉強したいから、書籍代など負担してくれるところに入りたい
- 現場に駆り出されてからは放置プレイで、相談できる人も先輩も居ないので、自分の状況をちゃんと理解してくれるところで働きたい
上記内容に1つでも当てはまる場合は、ぜひご検討ください。
プロパティとフィールドの違い
プロパティとフィールドの違いは以下2つ。
- アクセサが付いているかついてないか
- フィールドにアクセスするためのものかどうか
プロパティにはセッターとゲッターというアクセサがついている
まず、プロパティとフィールドの書き方です。
public int hoge; // フィールド
public int Hoge { get; set; } // プロパティ
見た通り、プロパティはget、setのアクセサがついたもので、フィールドはこのアクセサがついてないもの。
しかし、このプロパティですが、実は内部的にコンパイラーがフィールドを生成しており、見えないフィールドに対して値の受け渡しをしています。
プロパティとバッキングフィールド
「プロパティは内部的にコンパイラーがフィールドを生成している」と説明しましたが、プロパティに値をセットするときは以下と同様の動きをしています。
private int _hoge; // バッキングフィールド
public int Hoge
{
get
{
return _hoge;
}
set
{
_hoge = value;
}
}
プロパティにはバッキングフィールド(BackingField)というフィールドが用意されており、このバッキングフィールドに対して値の操作を行う仕組みがプロパティです。
コードを見るとget時はバッキングフィールドをreturnで返し、set時はHogeプロパティに代入した値がvalueとして渡され、バッキングフィールドにセットされていますね。
要は「プロパティはフィールドにアクセスするためのもの」ということになります。
フィールドを書かなくても、実は見えないフィールドが作られていて、プロパティはそのフィールドに対してアクセスをしているんですね!
プロパティとフィールドの使い分け方
オブジェクト指向においてフィールドの値を外部から変更させたり、参照させないために、「カプセル化」というものが重要になってきます。
そのため、フィールドは必ずprivateで書き、このフィールドにアクセスするためのプロパティをpublicで書きましょう。
フィールドの値を参照したり、変更する場合は必ずプロパティを経由するようにしてください。
以下のようにフィールドの値を参照、またはセットする前に何か処理を入れることもできます。
private int _hoge; // プロパティHogeで操作するバッキングフィールド
public int Hoge
{
get
{
return _hoge + 2;
}
set
{
_hoge = value * 2;
}
}
XamarinのSetPropertyなど、データバインディングするために利用することもありますね。
private int _hoge;
public int Hoge
{
get
{
return _hoge + 2;
}
set
{
SetProperty(ref _hoge, value);
}
}
その他プロパティの書き方
gtter、setterのみで書く
とくにフィールドを操作することがないのであれば、シンプルに
public int Hoge { get; set; }
といった書き方でいいと思います。
セッターをprivate
にすることで、外部からの値の変更を防ぐ書き方もできます。
public int Hoge { get; private set; }
ラムダ式で書く
フィールドを操作するときは、以下のようにラムダ式でスッキリ書くこともできるので覚えておきましょう。
(C#7.0以降)
private int _hoge;
public int Hoge
{
get => _hoge + 2;
set => _hoge = value * 2;
}
ちなみにgetterだけならこれでOK。
private int _hoge;
public int Hoge => _hoge + 2;
プロパティとフィールドの速度の違い
プロパティとフィールドの違いを調べていると「速度」というキーワードが気になったのでついでに試してみました。
下記の記事によるとプロパティのほうが速いと記載してあります。
下記コードで試してみました。
private int _hoge;
public int Hoge { get; set; }
public void Field()
{
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 1000000000; i++)
{
_hoge = 1000;
}
sw.Stop();
Console.WriteLine($"Field :{sw.ElapsedMilliseconds} ms");
}
public void Property()
{
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 1000000000; i++)
{
Hoge = 1000;
}
sw.Stop();
Console.WriteLine($"Property :{sw.ElapsedMilliseconds} ms");
}
シンプルにフィールド、プロパティそれぞれに値を10億回代入する処理です。
それぞれ最後まで代入し終わる時間をストップウォッチで測ります。
結果は以下のようになりました。
Field :1252 ms
Property :1937 ms
一応参考記事のコードを丸コピして実行。
Total field : 10000000000 : 47301 ms
Total properties : 10000000000 : 78750 ms
「使っているのがMacだからかなぁ」とか「.Net Core3.1だからかなぁ」とか考えてWindowsで試したり.Net Core5.0でやってみたり、コメントアウトしてフィールドのみとプロパティのみで計測してみたりしてみましたが結果は変わらずでした。
なぜフィールドのほうが速いのか
結果、フィールドのほうが速かったわけですが、なぜフィールドが速いのでしょう。
プロパティとフィールドにはアクセサを通るかどうかの違いがあるので、直接的か間接的かの違いで速さが変わるのだと思います。
そこで、以下のような直接値をセットするか、メソッドを経由してセットするかのコードで試してみました。
private int _hoge;
public void FieldOnly()
{
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 1000000000; i++)
{
_hoge = 1000;
}
sw.Stop();
Console.WriteLine($"FieldOnly :{sw.ElapsedMilliseconds} ms");
}
public void FieldAndMethod()
{
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 1000000000; i++)
{
SetField(1000);
}
sw.Stop();
Console.WriteLine($"FieldAndMethod :{sw.ElapsedMilliseconds} ms");
}
private void SetField(int value)
{
_hoge = value;
}
結果は...
FieldOnly :1264 ms
FieldAndMethod :1944 ms
やっぱメソッドを経由するので遅いですよね。
まぁそうゆうことだと思います。
まとめ
プロパティはフィールドのアクセサであり、カプセル化には必要不可欠なものだということがわかりました。
フィールドが必要な場合や、必要ない場合など様々なので、case-by-caseで使い分けていきまししょう。
以上、プロパティが何者かかということと、プロパティとフィールドの違いについてでした!
と思った方はコメントいただけると嬉しいです。
最後までお読みいただきありがとうございました!
私が働く会社では、一緒に働いてくれるエンジニアを募集しています♪
- 未経験、第二新卒歓迎
- 学歴・転職回数・離職期間不問
- 残業は月15時間以下で残業代は全額支給
- 経験者は月給23万円以上
- 年収100万以上UP↑↑↑も可能
- 長く働いていても年収が全然上がらないから、一気に年収を上げたい
- 残業をしたくてしているわけではないので、残業代はしっかりと出して欲しい
- やりたいことに挑戦させてもらえないから、自分がしてみたいことに挑戦したい
- 通勤時間が長すぎるから、できるだけ短くしたい
- もっと勉強したいから、書籍代など負担してくれるところに入りたい
- 現場に駆り出されてからは放置プレイで、相談できる人も先輩も居ないので、自分の状況をちゃんと理解してくれるところで働きたい
上記内容に1つでも当てはまる場合は、ぜひご検討ください。