今回は「拡張プロパティ」について見ていきます。extension ブロックには、拡張メソッドをグルーピングして整理できるという側面に加えて、通常のクラスと同じようにプロパティを書けるようになったという側面があります。これまでの拡張メソッドは、名前のとおりメソッドしか書けませんでしたが、extension ブロックの登場によってプロパティも書けるようになりました。
これまでの拡張メソッド
まずは int 型を拡張する extension ブロックに、IsZero と IsNegative という2つのメソッドが定義されている状態です。どちらも bool を返すだけの、値を判定するメソッドです。
図1 IsZero・IsNegative を通常のメソッドとして定義した状態
public static class Ex
{
extension(int value)
{
public bool IsZero()
{
return value == 0;
}
public bool IsNegative()
{
return value < 0;
}
}
}
メソッドをプロパティに書き換える
IsZero は、ただ値を返すだけで引数も取らないので、メソッドというよりプロパティとして書くほうが自然です。まず () を外すと、get アクセサーがない状態になりエラーになります。
そこで get { } を追加し、その中に return value == 0; を移動させることで、IsZero を正しいプロパティとして定義できます。
図2 () を外して get アクセサーを追加している途中の状態
図3 get アクセサーを持つプロパティとして完成した IsZero
プロパティの中身は return value == 0; だけなので、次のように => を使ったシンプルな書き方に整理できます。
図4 式形式(=>)で簡潔に書き直した IsZero プロパティ
public static class Ex
{
extension(int value)
{
public bool IsZero => value == 0;
public bool IsNegative()
{
return value < 0;
}
}
}
プロパティとして使う
IsZero をプロパティにしたことで、呼び出し方も変わります。a.IsZero() のように () を付けて呼び出すとエラーになり、a.IsZero と () なしで呼び出すのが正しい書き方になります。
図5 a.IsZero() と () を付けて呼び出そうとしてエラーになっている状態
図6 a.IsZero と () なしで呼び出す、正しい使い方
if 文の条件式で使う場合も、if (a.IsZero) のように書けます。ただ bool を返すだけの判定にメソッドの () が付いていると違和感がありますが、プロパティであれば自然な書き方になります。
int a = -1;
bool ret1 = a.IsZero;
if (a.IsZero)
{
ret1 = false;
}
int b = 0;
bool ret2 = b.IsNegative();
既存の拡張メソッドとの違い
ちなみに IEnumerable<T> の Any() や Count() には () が付いています。これらも中身は拡張メソッドで、実装を見ると this IEnumerable<TSource> source という形でメソッドとして定義されています。
図7 System.Linq.Enumerable の Any メソッドの定義。this を使った拡張メソッドとして実装されている
Any() が作られた当時は extension ブロックが存在しなかったため、拡張メソッドとしてはメソッドしか書けませんでした。そのため IEnumerable<T> の IsEmpty のような、値を保持しているだけのような判定であっても、() を付けて呼び出すメソッドとして書くしかなかった、ということになります。
図8 list.Any() を使って実装された IsEmpty メソッド。今までどおり () を付けて呼び出す
extension<T>(IEnumerable<T> list)
{
public bool IsEmpty()
{
if (list == null) return true;
return !list.Any();
}
}
まとめ
今後は extension ブロックが使えるので、値を保持しているだけの、変数のように使うものはプロパティとして書くほうが適しています。プロパティに適しているものを extension ブロックの中でプロパティとして定義することで、より自然で違和感のないコードが書けるようになりました。
Udemyでの動画版はこちらからご覧いただけます
00_はじめに
01_VisualStudio2026をインストールしてください
A01_fieldキーワード
B01_extensionブロックとは
B02_拡張メソッドとは
B03_extensionブロック
B04_型パラメータありの拡張メソッド
B05_型パラメータありのextensionブロックの書き方
B06_拡張プロパティ
B07_拡張静的プロパティ&メソッド
B08_拡張演算子
C01_partialコンストラクター
C02_幽霊コードを定義パーツで契約による実装をするという考え方
C03_partialイベント
D01_Null条件付き代入
E01_複合代入演算子のオーバーロード
F01_明示的な型を指定せずにラムダパラメータでパラメータ修飾子を使用する
G01_nameofはバインドされていないジェネリック型をサポートします
H01_SpanTおよびReadOnlySpanTのより暗黙的な変換
Udemyでの動画版はこちらからご覧いただけます