extension
ブロック
静的メソッド、インスタンスプロパティ、静的プロパティの拡張がサポートされ、これまで以上に多彩な拡張が可能になりました。
C# 13まではメソッドのみが拡張可能でした。
public static class Extensions
{
public static IEnumerable<int> WhereGreaterThan(this IEnumerable<int> source, int threshold)
=> source.Where(x => x > threshold);
}
この例では、this
キーワードが付けられたsource
パラメーターがレシーバーです。しかしプロパティ宣言には、同じようなレシーバーの指定場所がありません。そこでC# 14では「extension
ブロック」が導入されました。これは、レシーバーをそのブロック内のメンバーに公開するスコープです。
先ほどのWhereGreaterThan
メソッドを書き換え、さらにIsEmpty
プロパティを追加すると以下のようになります。
public static class Extensions
{
extension(IEnumerable<int> source)
{
public IEnumerable<int> WhereGreaterThan(int threshold)
=> source.Where(x => x > threshold);
public bool IsEmpty
=> !source.Any();
}
}
使い方は簡単です。
var list = new List<int> { 1, 2, 3, 4, 5 };
var large = list.WhereGreaterThan(3);
if (large.IsEmpty)
{
Console.WriteLine("No large numbers");
}
else
{
Console.WriteLine("Found large numbers");
}
ジェネリックにも対応しており、解決ルールは従来の拡張メソッドと同じです。以下のようにWhereGreaterThan
とIsEmpty
をジェネリックにすることもできます。
ここでINumber<T>
の制約は、> 演算子を使用可能にするために必要です。
extension<T>(IEnumerable<T> source)
where T : INumber<T>
{
public IEnumerable<T> WhereGreaterThan(T threshold)
=> source.Where(x => x > threshold);
public bool IsEmpty
=> !source.Any();
}
静的メソッドや静的プロパティにはレシーバーが不要なので、extension
ブロックでは型だけを指定します。
extension<T>(List<T>)
{
public static List<T> Create()
=> [];
}
extension
ブロックはこれまでの拡張メソッドと共存可能です。既存の構文に変える必要はなく、両者はまったく同じように実行されます。
既存の拡張メソッドを含む静的クラスにextension
ブロックを追加するだけでOKです。
public static class MyExtensions
{
// 従来の拡張メソッド
public static IEnumerable<int> WhereEven(this IEnumerable<int> source)
=> source.Where(x => x % 2 == 0);
// 新構文:extension ブロック
extension(IEnumerable<int> source)
{
public bool IsEmpty => !source.Any();
public int SumAll() => source.Sum();
}
// 静的メンバーの拡張(新構文)
extension<T>(List<T>)
{
public static List<T> CreateEmpty() => new List<T>();
}
}
今後のリリースではさらに多くの拡張がサポートされる予定とのこと。
Null条件付き代入
null条件演算子「?.」を右辺値(読み取り)だけでなく、左辺値(代入対象)でも使用できるようになります。
以下のようなUpdateAge
メソッドを例にします
public class Customer
{
public string Name { get; set; }
public int Age { get; set; }
}
public class UpdateCustomer
{
public static void UpdateAge(Customer? customer, int newAge)
{
if (customer is not null)
{
customer.Age = newAge;
}
}
}
Null条件付き代入を使うことで、UpdateAge
メソッドを以下のように書き換えることが可能になります。customer
がnull
でなければAge
を更新し、null
であれば何もしません。
public static void UpdateAge(Customer? customer, int newAge)
{
customer?.Age = newAge;
}
IDEが、この変更を提案するために電球アイコンでサポートしてくれるようになるそうです。