2009-04-01 10 views
65

C++テンプレートでは、特定の型パラメータがデフォルトであることを指定できます。私。明示的に指定されない限り、タイプTを使用します。C#Genericsの "default"型パラメータへの妥当なアプローチはありますか?

これはC#で行うことができますか近似できますか?

私のようなものを探しています:だから、明示的に指定していないタイプのインスタンスがT2こと

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

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

は以下のようになり、本質的に:

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

最終的に私はかなり広い範囲のテンプレートがあるケースを見ていますsedですが、追加の型パラメータを使用して拡張を検討しています。私はサブクラス化することができたと思いますが、この静脈に他の選択肢があるかどうか不思議でした。

答えて

61

サブクラス化が最適です。

私はあなたの主なジェネリッククラスをサブクラス化します:特定のクラスと

​​

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

これは一つの場所(基底クラス)で、あなたのロジックを維持することが容易になります両方の使用方法を提供することも容易です。クラスによっては、これを実現するために必要な作業はほとんどありません。

+1

ああ...それは理にかなっているようにあなたは、クラスのオーバーロードを作成することができます。型パラメータが一意の署名を提供する場合、型名は同じにすることができますか? – el2iot2

+2

@ee:はい、ジェネリックはパラメータカウントで「オーバーロード可能」です。 –

+0

@ee:そうですが、私はそれに気をつけています。これは.NETでは "合法"ですが、混乱を招く可能性があります。私はむしろ、文字列型の名前を主なジェネリッククラスと似ているようにしたいので(それは明白です)、文字列であることが明白になる名前です。 –

6

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

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

1

残念ながら、C#はあなたがしようとしていることをサポートしていません。パラメータのデフォルトの型がジェネリック制約に従う必要があり、CLRが型安全性を保証しようとしたときに頭痛を引き起こす可能性が高いので、実装するのは難しい機能です。

+1

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

+0

コンパイラは、デフォルトパラメータがジェネリック制約を満たすことを保証する必要があります。また、メソッドの型パラメーターについて行われた仮定では、デフォルト以外の型パラメーターが継承される必要があるため、デフォルトパラメーターは汎用制約そのものになります。 –

+0

@Andrewの場合、デフォルトのパラメータは一般的な制約である必要はありません。これは、より多くのC++のデフォルトのテンプレートパラメータのように動作した場合、その後automatonicのクラスにより拡張それは完全に罰金を行うだろう: MyTemplateに X =ヌル T2は全く一般的な制約を持っていないので、フロートは、文字列のデフォルトタイプにもかかわらず、結構ですので。このように、デフォルトのテンプレートパラメータは、MyTemplate の省略形として、MyTemplate を書き込むための本質的に単なる「構文上の砂糖」です。 –

13

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

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>(); 

タイプMyTemplate<int,string>なくのそれに由来するタイプです。

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

+3

これは最も有用なアプローチです。非常に良い解決策 –

8

ので

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

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

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

+4

受け入れられた答えが異なる名前のクラスを作成していましたが、私の解決策は同じクラスをオーバーロードしています – Moes

+1

いいえ、両方とも新しいクラスを作成しています。名前はここでは関係ありません。 'MyTemplate 'は 'MyTemplate 'とは異なるクラスであり、 'AnotherTemplate 'もありません。 –

関連する問題