Open ufcpp opened 3 months ago
昔ちょこっと書いたの:
C# 3.0 の拡張メソッドはインスタンス メソッドでだけ「既存の型に追加したように見える書き方」ができます。
123.Extension()
とはできても、int.Extension()
とはできません。
既存の型に静的メソッドを足せなくて困る例としては、ポリフィル(古い環境向けに最新機能を移植して使えるようにするような用途)とかでしょうか。
例えば割かし最近(.NET 8、2023年11月正式リリース)、TimeProvider
という型が入って以下のような書き方ができるようになりました。
TimeProvider tp = TimeProvider.System; // 1秒待つ。 // TimeProvider を差し替えて、単体テストとかでは一瞬で終わるようにしたい。 await Task.Delay(TimeSpan.FromSeconds(1), tp);
TimeProvider
クラス自体は、.NET 8 より前のランタイムでも使えるようにできます。
(実際、Microsoft.Bcl.TimeProvider
という NuGet パッケージが公式提供されています。)
以下のような書き方で、「なければ追加、あれば type forward」みたいなことができます。
#if NET8_0_OR_GREATER using System; using System.Runtime.CompilerServices; [assembly: TypeForwardedTo(typeof(TimeProvider))] #else namespace System; public class TimeProvider { // 互換実装 } #endif
インスタンス メソッドの追加風のことも、拡張メソッドでできました。
using System.Runtime.CompilerServices; namespace System.Threading.Tasks; public static class TaskExtensions { // GetAwaiter メソッドがあると C# 5.0 の await が使える。 public static TaskAwaiter GetAwaiter(this Task task) { // 今はインスタンス メソッドで GetAwaiter があるけど、 // .NET Framework 4.0 以前はなかったので自作が必要。 return task.GetAwaiter(); } }
ですが、先ほどの例に出てきた Task.Delay(TimeSpan, TimeProvider)
は既存の型への静的メソッドの追加なので、
これまでの C# ではどうやってもできませんでした。
13から外れた。 Unsafe.As 路線は JIT を混乱させて文字通り安全じゃないらしく、急遽路線変更。
https://ufcpp.net/blog/2024/3/extensions/