3

我有两个类(即CustomerEmployee)和一个通用存储库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);

在 linqpad 中,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

你当然可以。您可能还需要一个到您的存储库的接口。这有两个目的。首先,您可以以类型安全的语言绑定方式调用方法,而不必动态调用,其次,它允许您轻松地模拟它以进行测试。

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

您可以使用反射来创建通用对象,例如,您可以使用字符串来查找类型(使用 System.Type.GetType)。一旦你有了一个类型对象,你就可以使用它从反射 API 中找到一个构造函数 - 请参阅

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

于 2012-10-24T13:36:18.007 回答
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 回答
0

您不能像示例希望的那样直接执行此操作,但您可以实现工厂模式来帮助您。只需将字符串传递到您的工厂即可返回存储库。

编辑:工厂将拥有存储库中所有类(即客户和员工)的字典,这些类将在实例化时加载。我建议使用属性和反射,以便您可以动态地填充字典。然后,您有一个方法接收返回类型为 GenericRepository 的字符串的方法,其中字符串对应于字典中的一种类型。然后,您创建该 GenericRepository 的一个实例并将其返回给您的调用者。

于 2012-10-24T13:31:09.350 回答
0

您可以使用Type.GetType(string)来获取“客户”的类型定义。调用它时,它通常至少需要完整的命名空间。然后您可以在调用中使用该类型Type.MakeGenericType(params Type[])来创建泛型类型的类型定义。最后,Invoke(object[])对您新创建的类型的调用应该会创建一个 this 的实例。

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 回答