この章のテーマ §
プロパティとフィールドを学びます。これらは型に含まれる値を記録するメンバーです。
前提知識 §
Console.WriteLineメソッド, 文字列の基礎, 変数の基礎, クラスの基礎, string型
解説 §
クラスなどのメンバーとして、変数に準じる値を記録する機能を追加できます。
その方法は2つあります。フィールドとプロパティです。
フィールドとは、変数とほぼ同じように単なる値の入れ物です。
プロパティは、単なる値の入れ物としても使えますが、読み書きを実行するコードを記述することもできる高機能の別機能です。
一般的に、型の外部に公開しないものはフィールドを、公開するものはプロパティを使うことが多いようです。
書き方ですが、フィールドは特に何も追加しませんが、プロパティはsetキーワードとgetキーワードを使って書きます。setは書き込みの時に呼ばれvalueが書き込まれた値になります。getは読み出しの時に呼ばれreturnで読み出されるべき値を返します。set/getに対応するコードを書かないと【自動実装プロパティ】となり、暗黙的に宣言されたフィールドを読み書きするコードがあると見なされます。
読み出し専用にするときは、フィールドの場合はreadonlyキーワードを追加しますが、プロパティではsetキーワードを使いません。
プロパティは波括弧を取って=>演算子を書くことで式形式にすることもできますが、フィールドで同じことはできません。
罠の数々 §
- 読み出し専用のフィールド、プロパティはconstキーワードで定義する定数に似ている。しかし利用目的が違う。定数は永遠に書き換えられない値を扱うが、読み出し専用のフィールド、プロパティは初期化時に値が決まり、それ以降書き換えが許されないだけである。また、プロパティの場合は読み出されるごとに値が変わる読み出し線用プロパティを作ることもできる
- プロパティは、内部の実装が変わっても、外部に対しては何も変わっていないように見せかけるために便利である。何も変わっていないかのように見せかけるコードを書いてしまえば良いからだ。だから、公開されるメンバーにはプロパティが好まれる
- 読み出し専用のメンバーに限ってはreadonly付きのフィールドでも構わないという考え方もある
- フィールドとプロパティは、利用する側から見て良く似ているが、文法的に等価ではないことに注意しよう。希に片方しか使えない機能が存在する
参考リンク §
プロパティ (C# プログラミング ガイド)
フィールド (C# プログラミング ガイド)
サンプルソース: property_and_field §
var x = new MySample();
x.NameByField = "フィーちゃん";
x.NameByProperty = "プロパちゃん";
Console.WriteLine($"x.NameByField={x.NameByField}");
Console.WriteLine($"x.NameByProperty={x.NameByProperty}");
Console.WriteLine($"x.NameByFullProperty={x.NameByFullProperty}");
Console.WriteLine($"x.NameByExpressionProperty={x.NameByExpressionProperty}");
Console.WriteLine($"x.NameByReadOnlyField={x.NameByReadOnlyField}");
Console.WriteLine($"x.NameByReadOnlyProperty={x.NameByReadOnlyProperty}");
Console.WriteLine($"x.NameByReadOnlyExpressionProperty={x.NameByReadOnlyExpressionProperty}");
class MySample
{
// フィールドの例
public string NameByField = "フィールド";
public string NameByProperty { get; set; } = "プロパティ";
// 内容を含むプロパティの例
private string nameByFullProperty = "プロパティで読み出すフィールド";
public string NameByFullProperty { get { return nameByFullProperty; } set { nameByFullProperty = value; } }
// 内容を含むプロパティの式形式の例
public string NameByExpressionProperty { get => nameByFullProperty; set => nameByFullProperty = value; }
// 読み出し専用フィールドの例
public readonly string NameByReadOnlyField = "読み出し専用フィールド";
// 読み出し専用プロパティの例
public string NameByReadOnlyProperty { get; } = "読み出し専用プロパティ";
// 読み出し専用プロパティの式形式の例
public string NameByReadOnlyExpressionProperty { get => "読み出し専用プロパティ"; }
}
実行結果 §
x.NameByField=フィーちゃん
x.NameByProperty=プロパちゃん
x.NameByFullProperty=プロパティで読み出すフィールド
x.NameByExpressionProperty=プロパティで読み出すフィールド
x.NameByReadOnlyField=読み出し専用フィールド
x.NameByReadOnlyProperty=読み出し専用プロパティ
x.NameByReadOnlyExpressionProperty=読み出し専用プロパティ
リポジトリ §
https://github.com/autumn009/CSharpPrimer2
練習問題 §
以下のプログラムは許されるだろうか?
ただし、赤青緑の3つの値だけ記憶したいとする。
var a = new MySample();
a.X = "赤";
Console.WriteLine(a.X);
class MySample
{
private int x;
public string X
{
get => x switch { 0 => "赤", 1 => "青", _ => "緑" };
set => x = value switch { "赤" => 0, "青" => 1, _ => 2 };
}
}
- 許されない。stringで受けているのにintで記憶するので、型が一致しないというエラーになる
- 許される。見かけ上の辻褄が合っていれば良い
[[解答]]