IFROAble あらため IMath

やはり、すでに人様の日記*1のコメントで書いているのですが、

interface IMath 
  where T : IComparable, IFormattable, IConvertible, IComparable
{
  T Add(left T, right T);
}

などとしたとき、プリミティブ数値型はすべて上記インターフェスを実装しているので、IMath の実装クラス*2にはまったく変更なく実装が行われます。
しかし、IMath<T> を利用するクラスを作成するとき、

public class PrimitiveArray
  where T : IComparable, IFormattable, IConvertible, IComparable
  where I : IMath
{
}

などと制約を複製しないかぎりコンパイルエラーになります。この制約の複製はコンパイルエラーから簡単に判断できるので、書き忘れることも書くために調べ物をすることもないので我慢できる範囲ではあります。
しかし、前述したオーバーロード解決の問題で、IComparable と IComparable<T> のメソッドを解決するのがちょっと面倒です。
最初は IMath`1!0 の制約から IComparable を抜いて object 型で解決しようかとも思いましたが、数値型が対象であることを考えると、互換性のある型との親和性が微妙になりますが、ボックス化が発生する IComparable よりも IComparable を利用した比較を行いたいはずです。
少し悩みましたが現在は、

// IMath では制約を設けない
public interface IMath where T : struct { ... }
public struct MathUtils : IMath, IMath, ... { ... }

// T.CompareTo() を利用したい実装を行う場合
public class PrimitiveArray
  where T : struct, IComparable
  where I : IMath
{
  // このクラスの実装では CompareTo() できる
}

と、制約を行うのは利用側に委ねる事にしました。
これが自然ですよね? ね?

*1:毎回同じ方ですいません

*2:現在はクラス名 MathUtils