2009-03-26 22 views
15

私はそれのようなジェネリッククラスを持っています:C#で文字列から汎用クラスを作成するにはどうすればよいですか?

public class Repository<T> {...} 

そして、それをインスタンス化する必要があります... 例:

string _sample = "TypeRepository"; 
var _rep = new Repository<sample>(); 

どうすればいいですか?それも可能ですか?

ありがとう!

+0

あなたのプログラムでリポジトリを参照することはできませんので、_repのタイプは 'object'またはすべてのリポジトリに共通のインタフェースでなければなりません。 –

答えて

24

は、ここに私の2セントです。

MethodInfo genericMethod = repositoryType.GetMethod("GetMeSomething"); 
MethidInfo closedMethod = genericMethod.MakeGenericMethod(typeof(Something)); 
closedMethod.Invoke(repository, new[] { "Query String" }); 
+0

そして、どのようにしてリポジトリメソッドにアクセスできますか? – Paul

+2

リフレクションを使用して、実行時にしか知られていないタイプのリポジトリを作成したのと同じ方法です。あなたは柔軟性を求めて、あなたはそれを支払う必要があります。 – alex

+0

これを行う方法を教えてもらえますか? ありがとう! – Paul

-3

Genericクラスの "T"は、型のインスタンスであり、型のインスタンスではありません。あなたのリポジトリが文字列オブジェクトを保持したいのであれば、その後、

var _rep = new Repository<string>(); 
+0

私はあなたが質問を誤解したと思います。文字列には型名が含まれています。 –

16

を初めて使用するには、ジェネリック型を取得するためにtypeof(Repository<>).MakeGenericType(theTypeObject)を使用するとType.GetType(stringContainingTheGenericTypeArgument)

を使用してTypeオブジェクトを取得します。

そして最後には、これは可能 "の一種" であるActivator.CreateInstance

+0

本当の疑問は「彼には」すべきではありませんか? –

+0

文字列から生成型へ?おそらく。しかし、MakeGenericTypeは、linqプロバイダや他の式ツリー消費コードでよく使われます。それは素晴らしいヘルパーですが、毎日のLOBアプリではもちろんそれは心配するものではありません。 –

0

を使用しています。あなたがそれをやり遂げることができるという点で一種のものですが、それはちょっとしたハックです。

あなたは3つのオプションがあります:あなたがアップフロントあなたのクラスを知っている場合

を、switchステートメントを使用します。基本的には次のように:

switch(str){ 
    case "TypeRepository": return new Repository<TypeRepository>; 
} 

上記のより高度な形態として、あなたは、最大の柔軟性を高めるために代わりにハッシュテーブル

var factory = new Dictionary<string, Func<object>>(); 
factory.Add("TypeRepository",() => new Repository<TypeRepository>()); 

var theObject = factory["TypeRepository"]() as Repository<TypeRepository>; 

の辞書を使用することができ、あなたはクラスに文字列を一致させるためにリフレクションを使用することができます実行時にリフレクションはかなり遅いので、何らかの規則性でこれをやっているなら、それを避けたいと考えています。一例として、Frans Bouma'sメソッドを使用したものがここにあります。ちょうどあなたのコード内でRepository<>List<>を変更します。

public static object MakeList(string typeStr) 
{ 
    var nameSpace = "MyTestApplication" + "."; 

    var objType = Type.GetType(nameSpace + typeStr); // NAMESPACE IS REQUIRED 
    var listType = typeof(List<>).MakeGenericType(objType); 
    return Activator.CreateInstance(listType); 
} 

var listOfThings = MakeList("MyCoolObject") as List<MyCoolObject>; 

注:すべてのこれらのメカニズムはobjectを返すという事実を回避するための方法はありません、あなたがいうだけで強く型付けを返す返すよりも、あなたの適切な型にキャストする必要があり値。

実行時までリストの型がわからず、コンパイル時にC#が構築されているので、これはやむを得ないことです(これは「静的型付きプログラミング言語」と呼ばれます)。 C#4では痛みが少なく、dynamicを返すことができます。これにより、キャスティングが節約されます。

+0

型が文字列を使用して構築されているとすれば、C#はどのようにして特定の型を結果に合理的に関連付けますか? –

0

ジェネリックスはインスタンスではなくタイプで動作します。あなたはもっと読むことができますhere

あなただけの所望のタイプに取り、値をinitailizesあなたのクラスにコンストラクタを追加する必要があるような音:

public class Foo<T> 
{ 
    private T = default(T); 

    public Foo(T initValue) 
    { 
     _val = T; 
    } 
} 
2

私が正しくあなたの質問を理解していれば...何をしようとするですあなたのタイプ(Repository <T>)をとり、それを実行時に特定の一般的な実装で構成しますか?

もしそうなら、MakeGenericTypeを見てください。 Tのために必要なオブジェクトのtypeof(Repository)とSystem.Typeを使用して、このように構築できます。タイプを取得したら、Activator.CreateInstanceが機能します。コメントでの質問に答える

Type genericType = typeof(Repository<>); 
Type[] typeArgs = { Type.GetType("TypeRepository") }; 
Type repositoryType = genericType.MakeGenericType(typeArgs); 

object repository = Activator.CreateInstance(repositoryType); 

1
Type repType = typeof(Repository <>).MakeGenericType(Type.GetType("System.String")); 
object rep = Assembly.GetAssembly(repType).CreateInstance(repType.FullName); 

これはRepository<string>のインスタンスを作成します。 "System.String"は好きなタイプに置き換えることができます。

2

は、あなたの文字列が型の名前を保持している、あなたは

object _rep = Activator.CreateInstance(typeof(Repository<>).MakeGenericType(Type.GetType(_sample))); 

を書くことができると仮定しかし、_repは型なしオブジェクトになります、そして、あなたはそれで何かをする方法がありませんでしょう。ジェネリッククラスがコンパイル時にどの型であるかわからないので、それをキャストする型はありません。 (リポジトリが非ジェネリッククラスを継承するか、非ジェネリックインターフェイスを実装しない限り)

リポジトリの非ジェネリックベースクラスを作成し、そのオブジェクトをキャストすることで、それを解決できます。

ただし、状況によっては、Repositoryを非ジェネリッククラスにすることをお勧めします。

Repositoryが他のクラスを含むクラスの場合は、おそらく非ジェネリックにすることをお勧めします。そのコンストラクタにTypeオブジェクトを渡して、追加するオブジェクトごとにType.IsInstanceOfTypeを呼び出して、それが正しいタイプであることを確認してください。

リポジトリがカテゴリ化されたコレクションである場合、それを非ジェネリックにしてコンストラクタをstring categoryにするのが最も良い方法でしょう。

より具体的なアドバイスが必要な場合は、状況に関する詳細を投稿してください。

+0

マイリポジトリ: パブリッククラスリポジトリ:だから、それは不可能です... をIRepositoryWithTypedIdそして私はそのimplementantionを変更can't:RepositoryWithTypedId 、IRepository は{} publicクラスは RepositoryWithTypedId? – Paul

+0

私は上記のコード行を使用することは可能ですが、何かを行うことは非常に困難です。 なぜこれをしようとしていますか? '_rep'で何をやっていますか? – SLaks

+0

My _repはDAO(データアクセスオブジェクト)です... – Paul

3

これは、C#4.0から来るdynamicキーワードの仕事です。

あり、あなたのオブジェクトのインスタンスを取得しますここにいくつかの素敵なハックがありますが、それはので、それ自体でオブジェクトに多くを行うことはできませんどのようなC#の現在のバージョンは、それがobject持って知っている、とだけだろうどんなに現在のC#はレイトバインディングをサポートしていません。あなたはそれを使って何かをするために少なくともそれを既知の型にキャストすることができる必要があります。結局のところ、コンパイル時にが必要なタイプを知っていなければなりません。か、運が悪いです。あなたには、いくつかの既知のインターフェイスを実装する型にリポジトリクラスを制約することができるかどう

は今、あなたはより良い形にしています。

+0

だから、私の問題の解決策はありません... – Paul

+0

あなたのアーキテクチャを再考できない限り、C#4が出る前に本当にうまくいくものは得られません。 –

+2

これらのリポジトリオブジェクトと何をやりとりしたいのか分かれば、より効果的なデザインをお手伝いすることができます。 –

関連する問題