给定一个包含类名的字符串,如何在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'找不到"。所有的表都被定义为同一个命名空间中的类。

谢谢。

给定一个包含类名的字符串,如何在c#中使用该类作为类型参数调用泛型方法?

泛型类型参数必须是实际的类型名。它们不能是求值为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);