3

2つのクラス(つまり、、CustomerおよびEmployee)と汎用リポジトリがありますGenericRepository<T> where T : class

文字列からTの値を割り当てながら、新しいGenericRepositoryインスタンスをインスタンス化することは可能ですか?

このような:

string x  = "Customer";
var repository = new GenericRepository<x>();

(したがって、タイプのリポジトリインスタンスを作成しますGenericRepository<Customer>

4

6 に答える 6

11

はい、でもとてもむずかしいです。

string name = "MyNamespace.Customer";

Type targetType = Type.GetType(name);

Type genericType = typeof(GenericRepository<>).MakeGenericType( targetType );

object instance = Activator.CreateInstance(genericType);

リンクパッドでは、次のようになりinstance.Dump();ます。

GenericRepository<Customer> 
UserQuery+GenericRepository`1[UserQuery+Customer] 

編集

結果を動的に割り当てることができ、CreateInstanceリフレクションを通じてメソッドを呼び出す必要はありません。

dynamic instance = Activator.CreateInstance(genericType);
instance.SomeInstanceMethod(someParameter);
于 2012-10-24T13:35:02.613 に答える
2

できますよ。おそらく、リポジトリへのインターフェースも必要になるでしょう。これには2つの目的があります。まず、動的に呼び出すのではなく、型に安全な言語にバインドされた方法でメソッドを呼び出すことができます。次に、テストのために簡単にモックすることができます。

using System;
using System.Collections.Generic;

namespace QuickTest
{
    public interface IRepository
    {
        void test();
    }
    public class GenericRepositoryFactory
    {
        static public IRepository CreateInstance(params Type[] p)
        {
            Type genericType = typeof(GenericRepository<>).MakeGenericType(p);
            return Activator.CreateInstance(genericType) as IRepository;
        }
    }

    public class GenericRepository<t> : IRepository
    {
        public void test() { Console.WriteLine(this.GetType().ToString()); }
    }

    class Program
    {
        public static void Main(string[] argv)
        {
            var repo = GenericRepositoryFactory.CreateInstance(new[] { typeof(string) });
            repo.test();
        }
    }
}
于 2012-10-24T13:51:16.260 に答える
1

はい、可能です。以下にサンプル コードを示しますが、代わりにファクトリ パターンをお勧めします。

    internal class Program {

        private static void Main() {

            string customerString = @"Customer";
            string employeeString = @"Employee";

            object customerRepository = GetGenericRepository(customerString);
            object employeeRepository = GetGenericRepository(employeeString);

            System.Console.WriteLine();
        }

        public static object GetGenericRepository(string typeName) {

            // get the type from the string
            System.Type type = GetTypeFromName(typeName);

            System.Type repositoryOpenType = typeof(GenericRepository<>);
            System.Type repositoryClosedType = repositoryOpenType.MakeGenericType(type);

            return System.Activator.CreateInstance(repositoryClosedType);
        }

        // there are better methods for getting the type by name
        private static System.Type GetTypeFromName(string typeName) {

            System.Type type = System.Type.GetType(typeName, false);

            if (type == null) {

                var types = from assemblyType in System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
                            where assemblyType.Name == typeName
                            select assemblyType;

                type = types.FirstOrDefault();
            }

            return type;
        }
    }

    public class Customer {
    }

    public class Employee {
    }

    public class GenericRepository<T> where T : class {
    }
}
于 2012-10-24T13:56:50.657 に答える
1

リフレクションを使用して汎用オブジェクトを作成できます。たとえば、文字列を使用して型を検索できます (System.Type.GetType を使用)。型オブジェクトを取得したら、それを使用してリフレクション API からコンストラクターを見つけることができます - を参照してください。

http://msdn.microsoft.com/en-us/library/ms172334.aspx

于 2012-10-24T13:36:18.007 に答える
0

Type.GetType(string)「Customer」の型定義を取得するために使用できます。通常、呼び出すときは、少なくとも完全な名前空間が必要です。次に、その型を呼び出しで使用してType.MakeGenericType(params Type[])、ジェネリック型の型定義を作成できます。Invoke(object[])最後に、新しく作成した型を呼び出すと、このインスタンスが作成されます。

using System;

class Foo<T> where T : class { }

class Bar { }

class Program {
    static void Main(string[] args) {
        var barType = Type.GetType("ConsoleApplication29.Bar");
        var fooType = typeof(Foo<>).MakeGenericType(barType);
        var fooCtor = fooType.GetConstructor(Type.EmptyTypes);
        var instance = fooCtor.Invoke(new object[] { });
        Console.WriteLine(instance.GetType().FullName);
        Console.ReadLine();
    }
}
于 2012-10-24T13:38:04.887 に答える
0

あなたの例が望むように直接行うことはできませんが、ここで役立つように Factory パターンを実装できます。文字列をファクトリに渡すだけで、リポジトリが返されます。

編集: ファクトリには、リポジトリ内にあるすべてのクラス (つまり、Customer と Employee) の辞書があり、インスタンス化時にロードされます。ディクショナリを動的に設定できるように、属性とリフレクションを使用することをお勧めします。次に、文字列がディクショナリ内の型の 1 つに対応する GenericRepository 型の何かを返す文字列を受け取るメソッドがあります。次に、その GenericRepository のインスタンスを作成し、呼び出し元に返します。

于 2012-10-24T13:31:09.350 に答える