我有一个类似的Generic类:
public class Repository<T> {...}
我需要用字符串来实例化... 示例:
string _sample = "TypeRepository";
var _rep = new Repository<sample>();
我该怎么做?这甚至可能吗?
谢谢!
答案 0 :(得分:24)
这是我的2美分:
Type genericType = typeof(Repository<>);
Type[] typeArgs = { Type.GetType("TypeRepository") };
Type repositoryType = genericType.MakeGenericType(typeArgs);
object repository = Activator.CreateInstance(repositoryType);
回答评论中的问题。
MethodInfo genericMethod = repositoryType.GetMethod("GetMeSomething");
MethidInfo closedMethod = genericMethod.MakeGenericMethod(typeof(Something));
closedMethod.Invoke(repository, new[] { "Query String" });
答案 1 :(得分:16)
首先使用Type.GetType(stringContainingTheGenericTypeArgument)
然后使用typeof(Repository<>).MakeGenericType(theTypeObject)
获取通用类型。
最后使用Activator.CreateInstance
答案 2 :(得分:3)
这是C#4.0中dynamic
关键字的作业。
这里有一些不错的黑客可以让你获得你的对象的实例,但无论当前版本的C#只会知道它有一个object
,它对一个对象无能为力因为当前的C#不支持后期绑定。您需要能够至少将其转换为已知类型以对其执行任何操作。最终,您必须在编译时知道所需的类型,否则您将失去运气。
现在,如果您可以将您的存储库类限制为实现某个已知接口的类型,那么您的状态会更好。
答案 3 :(得分:2)
如果我正确理解你的问题......你要做的是拿你的类型(Repository&lt; T&gt;)并在运行时构建一个特定的通用实现?
如果是这样,请查看MakeGenericType。您可以使用typeof(Repository)和T所需对象的System.Type并以这种方式构造它。一旦你有了类型,Activator.CreateInstance将适合你。
答案 4 :(得分:2)
假设您的字符串包含类型的名称,您可以编写
object _rep = Activator.CreateInstance(typeof(Repository<>).MakeGenericType(Type.GetType(_sample)));
但是,_rep将是一个无类型的对象,你将无法用它做任何事情。由于您不知道泛型类在编译时的类型,因此没有将其强制转换为的类型。 (除非Repository继承非泛型类或实现非泛型接口)
您可以通过为Repository创建一个非泛型基类并将对象转换为它来解决这个问题。
但是,根据您的情况,您可能希望Repository
成为非泛型类。
如果Repository
是包含其他类的类,则最好将其设为非泛型。您可以使其构造函数采用Type
对象,然后在您添加的每个对象上调用Type.IsInstanceOfType
以确保它是正确的类型。
如果Repository是事物的分类集合,那么最好将其设置为非泛型,并使其构造函数采用string category
。
如果您需要更具体的建议,请发布有关您情况的更多详细信息。
答案 5 :(得分:1)
Type repType = typeof(Repository <>).MakeGenericType(Type.GetType("System.String"));
object rep = Assembly.GetAssembly(repType).CreateInstance(repType.FullName);
这将创建Repository<string>
的实例。您可以将“System.String”替换为您喜欢的任何类型。
答案 6 :(得分:0)
这有点“可行”。你可以做到这一点,但这有点像黑客。
您有3个选项:
如果您事先知道您的课程,请使用switch语句。基本上是这样的:
switch(str){
case "TypeRepository": return new Repository<TypeRepository>;
}
作为上述的更高级形式,您可以使用字典而不是哈希表
var factory = new Dictionary<string, Func<object>>();
factory.Add( "TypeRepository", () => new Repository<TypeRepository>() );
var theObject = factory["TypeRepository"]() as Repository<TypeRepository>;
为了获得最大的灵活性,您可以使用反射在运行时将字符串与类匹配。请注意,反射速度相当慢,因此如果您以任何规律性进行此操作,则需要避免反射。例如,这是使用Frans Bouma's方法的一个。只需在代码中将List<>
更改为Repository<>
:
public static object MakeList( string typeStr )
{
var nameSpace = "MyTestApplication" + ".";
var objType = Type.GetType(nameSpace + typeStr); // NAMESPACE IS REQUIRED
var listType = typeof(List<>).MakeGenericType(objType);
return Activator.CreateInstance(listType);
}
var listOfThings = MakeList("MyCoolObject") as List<MyCoolObject>;
注意:没有办法避免所有这些机制返回object
这一事实,然后你必须将其转换为正确的类型,而不是返回只返回强类型值。
这是不可避免的,因为在运行时你不知道列表的类型,而C#是在编译时知道事物的(这就是人们说“静态类型编程语言”时的意思)。在C#4中它会减少痛苦,你将能够返回dynamic
,这将为你节省一些力量。
答案 7 :(得分:0)
泛型可以处理类型,而不是实例。您可以阅读更多here。
听起来你只需要在你的类中添加一个构造函数,它接受所需类型并初始化值:
public class Foo<T>
{
private T = default(T);
public Foo(T initValue)
{
_val = T;
}
}
答案 8 :(得分:-3)
Generic类中的“T”代表类型,而不是类型的实例。因此,如果您希望存储库保存字符串对象,请使用
var _rep = new Repository<string>();