ufcpp/UfcppSample

Extensions

Opened this issue · 2 comments

昔ちょこっと書いたの:

要求1: 静的メンバー

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# ではどうやってもできませんでした。

ufcpp commented

13から外れた。
Unsafe.As 路線は JIT を混乱させて文字通り安全じゃないらしく、急遽路線変更。