我有两个类(即Customer
和Employee
)和一个通用存储库GenericRepository<T> where T : class
。
是否可以在从字符串中分配T的值时实例化新的GenericRepository实例?
像这样:
string x = "Customer";
var repository = new GenericRepository<x>();
(从而创建类型为GenericRepository<Customer>
)
答案 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中查找构造函数 - 参见
答案 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 {
}
}