2009-03-18 14 views
3

(おかげで答えをみんな、here is my refactored example、単一責任の原則について順番に別のStackOverflowの質問。)メソッドシグネチャでジェネリックを使用する利点は何ですか?

のC#にPHPから来て、この構文は威圧された:

container.RegisterType<Customer>("customer1"); 

私が実現するまで

container.RegisterType(typeof(Customer), "customer1"); 

私は以下のコードで実証しています。

のでタイプを送信するときに、ジェネリック医薬品は、(例えばUnityと最もC#IoCコンテナ全体で)それだけでクリーンな構文であること以外、つまりあなたが(typeof演算を必要としない)ここで使用される理由は?いくつかの理由がありますか

using System; 

namespace TestGenericParameter 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Container container = new Container(); 
      container.RegisterType<Customer>("test"); 
      container.RegisterType(typeof(Customer), "test"); 

      Console.ReadLine(); 
     } 
    } 

    public class Container 
    { 
     public void RegisterType<T>(string dummy) 
     { 
      Console.WriteLine("Type={0}, dummy={1}, name of class={2}", typeof(T), dummy, typeof(T).Name); 
     } 

     public void RegisterType(Type T, string dummy) 
     { 
      Console.WriteLine("Type={0}, dummy={1}, name of class={2}", T, dummy, T.Name); 
     } 

    } 

    public class Customer {} 
} 

//OUTPUT: 
//Type=TestGenericParameter.Customer, dummy=test, name of class=Customer 
//Type=TestGenericParameter.Customer, dummy=test, name of class=Customer 

答えて

5

主な理由は、コンパイル時の型の安全性です。 2つのTypeオブジェクトを渡す場合は、コンパイラではなく開発者が責任を負います。

これは、具体的な型が抽象型を継承していない場合にコンパイラが文句を言うため、多くのIoCコンテナがそれを利用する理由です。

public void Register<TAbstract, TConcrete>() where TConcrete : TAbstract 
{ 
} 

TConcreteが実装またはTAbstractを継承している場合は、このコードは動作します。このメソッドが2つのパラメータを取った場合、メソッドはこの関係を検証する必要があります。

3

は、一例として、一般的な対typeofオプションを使用して、型のインスタンスを作成するために必要なコードを比較します。または、型のインスタンスを返します。または、引数の型のインスタンスを受け入れます。または、型のインスタンスにプロパティを設定します。

通常、型自体でのみ作業する場合は、型パラメータを受け入れることができます。型のインスタンスで何かをしたい場合は、genericを使います。

ジェネリックを使用する別の理由は、タイプに制約を適用する場合です。たとえば、型に1つまたは複数のインタフェースを実装したり、別の型を継承したり、参照型または値型を指定したり、デフォルトコンストラクタを使用したり、上記の組み合わせを必要とすることができます。コンパイラはこれを強制しますので、要件に準拠していないコードを作成することはできません。

3

主な用途の1つは、型の安全性と引数と戻り値です。あなたの例では、入出力の型(文字列)が一般的なケース(顧客)と一致しないため、ジェネリックの使用はあまりありません。

より適切な使用があるかもしれない:ジェネリック型パラメータは、パラメータの種類として、またはとして使用する場合、ジェネリック医薬品は非常に便利です

public T RegisterType<T>(string name) 
{ 
    T obj = new T(); 
    obj.DoSomething(); 
    return obj; 
} 

または多分

public void DoSomething<T>(T obj) 
{ 
    //operate on obj 
} 
+0

非常に便利だが、実装しようとすると、 "T obj = new T();"私に "変数型 'T'のインスタンスを作成できません。なぜなら、new()制約がないからです。"私は何が欠けていますか? –

+1

あなたは私の答えのように制約を加える必要があります: 'public T CreateNew ()T:new()' –

4

一つの理由がありますメソッドの戻り値の型、あなたは

戻り値の型がコンパイラによって確認することができ、ボクシングの値の型が、時には回避することができ
public T GetAs<T>(string name) 

のようなメソッドを書くことができることを意味 。

int value = GetAs<int>("foo"); 

Whithoutジェネリック医薬品は、あなたが

public object GetAs(Type t, string name) 

を記述する必要がありますし、呼び出し側は、再び結果をキャストすることがあります: 呼び出し側が書くでしょう

int value = (int)GetAs(typeof(int), "foo"); 
2

あなたがしなかった場合ジェネリックスを使用する場合は、サポートするタイプごとにメソッドをオーバーロードするか、オブジェクトとして受け入れてキャストロジックを実行する必要があります。

4

簡単な答えはタイプ推論可能であればです。

ジェネリック型がメソッドのシグネチャで使用されている場合、あなたはそれを省略することができますタイプを推測される可能性があるため:

void SomeMethod<T>(T x, T y) where T : IComparable<T> { 
    Console.WriteLine("Result: {0} to {1} is {2}", x, y, x.CompareTo(y)); 
} 

ので、使用が簡素化されます。

SomeMethod(3, 4);   // instead of SomeMethod<int>(3, 4); 
SomeMethod("one", "two"); // instead of SomeMethod<string>("one", "two"); 

ジェネリック型の場合パラメータがメソッドシグネチャで使用されていない場合、型推論は不可能です:

var emptySequence = Enumerable.Empty<int>(); 
1

私は言うでしょう彼は、ジェネリック型が特定の型(またはサブクラス/実装者)であることを保証するために、 "where"キーワードを使用して、型の安全性を最大の理由としています。 "typeof"を使用すると何かを送ることができます。

関連する問題