【问题标题】:Given a string which holds the name of a class, how can I then call a generic method using that class as the type parameter in C#?给定一个包含类名称的字符串,然后如何使用该类作为 C# 中的类型参数调用泛型方法?
【发布时间】:2015-09-28 05:39:11
【问题描述】:

我在 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# generics methods types


    【解决方案1】:

    你可以用反射来做到这一点。

    How do I use reflection to call a generic method?

    使用您的代码示例:

    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);
    }
    

    【讨论】:

      【解决方案2】:

      首先,在调用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);
      

      【讨论】:

        【解决方案3】:

        泛型类型参数必须是实际的类型名称。它们不能是计算结果为 Type 对象的表达式。

        SQLite-Net 已经有一个non-generic overload of 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 的反射来调用带有来自表达式的 Type 的方法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多