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


91

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

これはC#で実行または概算できますか?

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

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

したがって、明示的に指定されていないタイプのインスタンスは次のようになりますT2

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

本質的に:

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

結局、かなり広く使われているテンプレートがあるのですが、typeパラメータを追加して拡張することを考えています。私はサブクラス化できると思いますが、この静脈に他のオプションがあるかどうか知りました。

回答:


76

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

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

class BaseGeneric<T,U>

特定のクラスで

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

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


1
ああ...それは理にかなっています。型パラメーターが一意の署名を提供する場合、型名を同じにすることはできますか?
el2iot2 2009

2
@ee:はい、ジェネリックスはoverloadableパラメーター数によるものです。
Mehrdad Afshari、

@ee:はい、しかし私はそうすることに警戒するでしょう。.NETではそうすることは「合法」ですが、混乱を招く可能性があります。文字列の派生型の名前はメインのジェネリッククラスに似ているので(何を検索するのが簡単であるのかがわかりやすい)、文字列であることを明確にする名前にする必要があります。
リードコプシー

@リード:それは本当に混乱につながるのですか?この特定のケースでは、同じ名前を付けることも役立つと思います。同じことを行う例が.NETにあります。たとえば、Func <>デリゲートです。
Mehrdad Afshari、

4
たとえば、Predicate <T>は単なるFunc <T、bool>ですが、別の目的のために名前が変更されています。
リードコプシー

19

1つの解決策はサブクラス化です。私が代わりに使用するもう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> あり、、それから派生した型では。

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


3
これが最も使いやすいアプローチです。非常に優れたソリューション
T-moty

12

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

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

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

おそらくあなたの解決策は他のものと同じであるため、遅い回答を投稿する前に他の回答を読んでください。
Cheng Chen

7
受け入れられた答えは異なる名前のクラスを作成することでした、私の解決策は同じクラスをオーバーロードすることです
Nerdroid

2
いいえ、どちらも新しいクラスを作成しています。名前はここでは関係ありません。MyTemplate<T1>はとは異なるクラスでありMyTemplate<T1, T2>、どちらでもありませんAnotherTemplate<T1>
Cheng Chen

7
実際のタイプが異なっていても、それは明確で正しいものですが、同じ名前を維持すると、コーディングが簡単になります。クラス「オーバーロード」がそのように使用できることは誰にとっても明白ではありません。@DannyChenは正しい-技術的な観点からは結果は同じですが、このanswearはOPが要求したことを達成するためにより近いです。
キューバ2017

1
残念ながら、このソリューションは、真の「デフォルト」の一般的な引数よりも劣っています。なぜなら、a MyTemplate<T1, string>をに割り当てることができないためです。MyTemplate<T1>これは望ましい場合があります
Felk

9

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

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


2

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


1
あんまり。これは(VB.NETのデフォルトパラメータのような)属性を使用して行うことができ、コンパイラにコンパイル時にそれを置き換えさせることができます。主な理由は、C#の設計目標です。
Mehrdad Afshari、

コンパイラーは、デフォルトのパラメーターが一般的な制約を満たすようにする必要があります。また、メソッド内の型パラメーターについて行われたすべての仮定では、デフォルト以外の型パラメーターがその型パラメーターを継承する必要があるため、デフォルトパラメーター自体が一般的な制約になります。
Andrew Hare

@Andrew、デフォルトのパラメータは一般的な制約である必要はありません。これがC ++のデフォルトのテンプレートパラメータのように動作する場合、オートマトンのクラスに拡張すると、完全に問題ありません。MyTemplate<int、float> x = null T2には一般的な制約がないため、デフォルトの文字列タイプにもかかわらずfloatは問題ありません。 。このように、デフォルトのテンプレートパラメータは基本的に、MyTemplate <int>をMyTemplate <int、string>の省略形として記述するための単なる「構文上の砂糖」です。
タイラーレイン2013年

@Andrew、私はC#コンパイラがそのようなデフォルトのテンプレートパラメータが既存の一般的な制約を満たすことを確認する必要があることに同意します。C#コンパイラは、クラス宣言で同様のことをすでに確認しています。たとえば、「where U:ISomeInterface」などの一般的な制約をReedのBaseGeneric <T、U>クラスに追加すると、MyGeneric <T>はエラーでコンパイルに失敗します。デフォルトのテンプレートパラメータの確認はほとんど同じです。コンパイラはクラスの宣言を確認し、エラーメッセージは同じか非常に似ています。
タイラーレイン2013年

「実装するのが難しい機能です」それはナンセンスです。実装するのは簡単です。候補の型がファイル内の別の場所(つまり、テンプレートのインスタンス化ではなくテンプレート)に表示されるため、テンプレートの制約に対して型を検証する作業は難しくなりません。
2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.