rksoftware

Visual Studio とか C# とかが好きです

C# 11 で Generic な算術演算を作る

C# 11 で 「 ジェネリック型数値演算のサポート 」 という新機能が追加されました。その中の 「 インターフェイスの static virtual メンバー 」 を書いて試してみたいと思います。

rksoftware.hatenablog.com

// Console.WriteLine(new SValue1(10) + new SValue1(5)); // エラー CS0019 演算子 '+' を 'SValue1' と 'SValue1' 型のオペランドに適用することはできません
Console.WriteLine(new SValue1(10) - new SValue1(5));  // SValue { Value = 5 }

Console.WriteLine(new SValue2(10) + new SValue2(5));  // SValue2 { Value = 15 }
Console.WriteLine(new SValue2(10) - new SValue2(5));  // SValue1 { Value = 5 }

// Console.WriteLine(new SValue2(10) + new SValue1(5));  // エラー CS0019 演算子 '+' を 'SValue2' と 'SValue1' 型のオペランドに適用することはできません
Console.WriteLine(new SValue2(10) - new SValue1(5));  // SValue1 { Value = 5 }

Console.WriteLine(new SValue3(10) + new SValue3(5));  // SValue2 { Value = 15 }
Console.WriteLine(new SValue3(10) - new SValue3(5));  // SValue1 { Value = 5 }

Console.WriteLine(new SValue4(10) + new SValue4(5));  // SValue4 { Value = 15 }
Console.WriteLine(new SValue4(10) - new SValue4(5));  // SValue4 { Value = 5 }

interface IInterface<T> where T:IInterface<T>
{
    static virtual T operator +(T arg1, T arg2) => arg1;
    static abstract T operator -(T arg1, T arg2);
}

record SValue1(int Value) : IInterface<SValue1>
{
    public static SValue1 operator -(SValue1 arg1, SValue1 arg2) => new SValue1((arg1?.Value??default) - (arg2?.Value??default));
}

record SValue2(int Value) : SValue1(Value)
{
    public static SValue2 operator +(SValue2 arg1, SValue2 arg2) => new SValue2((arg1?.Value ?? default) + (arg2?.Value ?? default));
}

record SValue3(int Value) : SValue2(Value)
{
}

record SValue4(int Value) : SValue3(Value)
{
    public static SValue4 operator -(SValue4 arg1, SValue4 arg2) => new SValue4((arg1?.Value ?? default) - (arg2?.Value ?? default));
    public static SValue4 operator +(SValue4 arg1, SValue4 arg2) => new SValue4((arg1?.Value ?? default) + (arg2?.Value ?? default));
}

こんな感じ。いいですね。

SValue1 の +

SValue1 の + は (virtual メソッドは実装を強制されない、実装していないので) コンパイルエラーです。

SValue2 と SValue1 の演算

型として base よりの SValue1 の演算が使われています。

SValue3 で実装のない演算

SValue2、SValue1 の演算が使われています。

SValue4 同士の演算

SValue4 で実装した演算が使われます。

■ 想像通り

想像通りの素直な分かりやすい結果となりました。いいですね。
ただし、実装がないと base の演算が行われるのでそこは注意ですね。