c#泛型。 <t>,以编程方式从读取字符串值?</t>中分配T.

时间:2012-10-24 13:27:23

标签: c# generics instantiation

我有两个类(即CustomerEmployee)和一个通用存储库GenericRepository<T> where T : class

是否可以在从字符串中分配T的值时实例化新的GenericRepository实例?

像这样:

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

(从而创建类型为GenericRepository<Customer>

的存储库实例

6 个答案:

答案 0 :(得分:10)

是的,但这很尴尬。

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

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

您可以使用Type.GetType(string)获取“客户”的类型定义。调用它时通常至少需要完整的命名空间。然后,您可以在调用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();
    }
}

答案 5 :(得分:0)

是的,有可能。下面是示例代码,但我建议使用工厂模式。

    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 {
    }
}