web-dev-qa-db-ja.com

C#Genericsの「デフォルト」型パラメーターに合理的なアプローチはありますか?

C++テンプレートでは、特定の型パラメーターがデフォルトであることを指定できます。つまり明示的に指定されない限り、タイプTが使用されます。

これはC#で実行または近似できますか?

私は次のようなものを探しています:

public class MyTemplate<T1, T2=string> {}

そのため、T2を明示的に指定しないタイプのインスタンス:

MyTemplate<int> t = new MyTemplate<int>();

基本的に:

MyTemplate<int, string> t = new MyTemplate<int, string>();

最終的には、かなり広く使用されているテンプレートがある場合を検討していますが、追加の型パラメーターで拡張することを検討しています。サブクラスはできたと思いますが、この方法に他のオプションがあるかどうか興味がありました。

77
el2iot2

サブクラス化が最適なオプションです。

メインのジェネリッククラスをサブクラス化します。

class BaseGeneric<T,U>

特定のクラスで

class MyGeneric<T> : BaseGeneric<T, string>

これにより、ロジックを1つの場所(基本クラス)に保持しやすくなりますが、両方の使用オプションを簡単に提供できます。クラスによっては、これを実現するために必要な余分な作業はほとんどありません。

70
Reed Copsey

1つの解決策はサブクラス化です。私が代わりに使用する別の方法は、ファクトリーメソッドです(varキーワードと組み合わせて)。

public class MyTemplate<T1,T2>
{
     public MyTemplate(..args..) { ... } // constructor
}

public static class MyTemplate{

     public static MyTemplate<T1,T2> Create<T1,T2>(..args..)
     {
         return new MyTemplate<T1, T2>(... params ...);
     }

     public static MyTemplate<T1, string> Create<T1>(...args...)
     {
         return new MyTemplate<T1, string>(... params ...);
     }
}

var val1 = MyTemplate.Create<int,decimal>();
var val2 = MyTemplate.Create<int>();

上記の例では、val2の型はMyTemplate<int,string>not notから派生した型です。

タイプclass MyStringTemplate<T>:MyTemplate<T,string>は、MyTemplate<T,string>と同じタイプではありません。これは、特定のシナリオでいくつかの問題を引き起こす可能性があります。たとえば、MyTemplate<T,string>のインスタンスをMyStringTemplate<T>にキャストすることはできません。

18

クラスオーバーロードを作成することもできます

public class MyTemplate<T1, T2> {
    public T1 Prop1 { get; set; }
    public T2 Prop2 { get; set; }
}

public class MyTemplate<T1> : MyTemplate<T1, string>{}
11
Moes

C#はそのような機能をサポートしていません。

あなたが言ったように、あなたはそれをサブクラス化することができます(それが封印されていなければ、そしてすべてのコンストラクタ宣言を複製します)が、それは完全に異なるものです。

8
Mehrdad Afshari

残念ながら、C#はあなたがやろうとしていることをサポートしていません。パラメーターの既定の型は一般的な制約に従う必要があり、CLRが型の安全性を確保しようとしたときに頭痛の種になる可能性が高いため、実装するのは難しい機能です。

2
Andrew Hare