我有两个类(即Customer
和Employee
)和一个通用存储库GenericRepository<T> where T : class
。
是否可以在从字符串分配 T 的值时实例化一个新的 GenericRepository 实例?
像这样:
string x = "Customer";
var repository = new GenericRepository<x>();
(从而创建类型的存储库实例GenericRepository<Customer>
)
我有两个类(即Customer
和Employee
)和一个通用存储库GenericRepository<T> where T : class
。
是否可以在从字符串分配 T 的值时实例化一个新的 GenericRepository 实例?
像这样:
string x = "Customer";
var repository = new GenericRepository<x>();
(从而创建类型的存储库实例GenericRepository<Customer>
)
是的,但这很尴尬。
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);
你当然可以。您可能还需要一个到您的存储库的接口。这有两个目的。首先,您可以以类型安全的语言绑定方式调用方法,而不必动态调用,其次,它允许您轻松地模拟它以进行测试。
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();
}
}
}
您可以使用反射来创建通用对象,例如,您可以使用字符串来查找类型(使用 System.Type.GetType)。一旦你有了一个类型对象,你就可以使用它从反射 API 中找到一个构造函数 - 请参阅
是的,有可能。下面的示例代码,但是我会推荐一个工厂模式。
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 {
}
}
您不能像示例希望的那样直接执行此操作,但您可以实现工厂模式来帮助您。只需将字符串传递到您的工厂即可返回存储库。
编辑:工厂将拥有存储库中所有类(即客户和员工)的字典,这些类将在实例化时加载。我建议使用属性和反射,以便您可以动态地填充字典。然后,您有一个方法接收返回类型为 GenericRepository 的字符串的方法,其中字符串对应于字典中的一种类型。然后,您创建该 GenericRepository 的一个实例并将其返回给您的调用者。
您可以使用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();
}
}