给定一个包含类名的字符串,如何在c#中使用该类作为类型参数调用泛型方法?
本文关键字:泛型方法 调用 类型参数 一个 包含类 字符串 | 更新日期: 2023-09-27 18:01:49
我在SQLite-Net中使用CreateTable方法,它需要一个类型参数来指定正在创建的表的类型。例如:
database.CreateTable<Client>();
其中客户端定义为:
[Table("Client")]
public class Client
{
[PrimaryKey]
public int ClientID { get; set; }
public string Name { get; set; }
public string Type { get; set; }
}
将使用客户端类中定义的模式创建一个表,因此具有ClientID、Name和Type列。
我想使用一个字符串数组,持有我想要创建的表的名称,在数组中命名的所有类上运行CreateTable。然而,我不确定如何在泛型方法中使用字符串作为类型参数。
它看起来像这样:
string[] tables = new string[]{"Class1","Class2"};
for(int i = 0; i < tables.Length; i++){
database.CreateTable<tables[i]>();
}
它的作用与下面的相同:
database.CreateTable<Class1>():
database.CreateTable<Class2>();
我已经试过这样做了:
Type tabletype = Type.GetType("Client");
database.CreateTable<tabletype>();
但是我得到一个错误,说"类型或名称空间名称'tabletype'找不到"。所有的表都被定义为同一个命名空间中的类。
谢谢。
泛型类型参数必须是实际的类型名。它们不能是求值为Type
对象的表达式。
SQLite-Net已经有一个CreateTable
的非泛型过载,您应该在这种情况下使用:
Type tabletype = Type.GetType("Client");
database.CreateTable(tabletype);
或
string[] tables = new[] { "Class1", "Class2" };
for(int i = 0; i < tables.Length; i++) {
Type tableType = Type.GetType(tables[i]);
database.CreateTable(tableType);
}
在更一般的情况下,您必须使用MakeGenericMethod
的反射来调用具有来自表达式的类型的方法。
您可以使用Reflection。
如何使用反射来调用泛型方法?
使用你的代码示例:
var database = GetDatabase(); // not sure what this type is.
MethodInfo method = database.GetType().GetMethod("CreateTable");
var assembly = Assembly.GetExecutingAssembly(); // Assume Class1, Class2 etc are here.
var tables = new string[] { "Class1","Class2" };
for(int i = 0; i < tables.Length; i++)
{
MethodInfo generic = method.MakeGenericMethod(assembly.GetType(tables[i]););
generic.Invoke(database, null);
}
首先,您的类型名称应该包括调用Type.GetType
时的名称空间,并且类型的全名应该是无歧义的:
public Type GetTableType(string name) {
const string NamespacePrefix = "MyApp.Tables.";
return Type.GetType(NamespacePrefix + name);
}
当您拥有类型时,您需要使用反射来调用泛型方法,因为没有办法在编译时确定类型:
string tableName = "BlaTable";
var genericMethodTemplate = database.GetType().GetMethod("CreateTable", new Type[0]);
//genericMethodTemplate can be seen as database.CreateTable<T>();
var tableType = GetTableType(tableName);
var genericMethod = genericMethodTemplate.MakeGenericMethod(tableType);
//now the T has been filled in with whatever table was given.
genericMethod.Invoke(database);