【问题标题】:Generic Type as a Variable作为变量的泛型类型
【发布时间】:2018-04-22 10:26:42
【问题描述】:

我有一个接受通用 T 类的方法

  public void CreateTables<T>()
   {
    string name = typeof(T).Name;

    var fields = typeof(T).GetProperties().Select(t => new { key = 
    t.Name.ToLower(CultureInfo.InvariantCulture), value = 
    SqLiteUtility.GetSQLiteTypeString(t.PropertyType) })
      .ToDictionary(t => t.key, t => 
          t.value);

    CreateTable(name, fields);
    }

   and 

    public void PushData<T>() where T : EntityData
   {
    var data = _context.Set<T>().Where(p => p.Deleted == false).ToList();
   }

我有超过 50 种类型需要像这样调用这个方法

CreateTables<Class1>();
PushData<Class1>();

虽然我可以这样做,但我更喜欢创建类型数组并使用 for 循环调用此方法

像这样的

   Type[] types=new Types[]{typeof(Class1),typeof(Class2)}

   foreach(var type in types)
   {
    //call create table method
      CreateTables<type>(); - - this doesnt work as "type" is a variable 
                                used as a type 

   }

有没有办法解决这个问题?这也可以为我节省大量代码并有效地重构东西?

编辑1:

从答案来看,像 CreateTables(Type T) 这样的参数确实可以工作,但是对于上面的第二种方法,是否也有可能?

在第二个中,重要的是提到 T 类型为 EntityData,因为方法中的代码依赖于它。

【问题讨论】:

  • 这些类有什么共同点可以让您使用反射找到它们吗?
  • 当您踏入反思的世界时,您通常无法轻易退出。要一般调用该方法,您必须使用反射来调用它。
  • 所以写CreateTables(Type),让CreateTables&lt;T&gt; 打电话给CreateTables(typeof(T))。您根本没有使用 T 在编译时可用这一事实,因此您不会失去任何表现力。
  • @TimothyGroote 他们都继承自同一个类。
  • 现在这个人有什么问题,问 7-10 岁的问题,每个人都喜欢:“哦,让我回答并获得投票,我什至不会搜索问题是否有答案。” ?

标签: c#


【解决方案1】:

基本上你是在尝试从反射到泛型再回到反射。

由于所讨论的方法只是简单地退回到反射中,因此更好的方法是创建采用类型的重载,如下所示:

public void CreateTables<T>()
{
    CreateTables(typeof(T));
}

public void CreateTables(Type tableType)
{
    string name = tableType.Name;

    var fields = tableType.GetProperties().Select(t => new
        {
            key = t.Name.ToLower(CultureInfo.InvariantCulture),
            value = SqLiteUtility.GetSQLiteTypeString(t.PropertyType)
        })
        .ToDictionary(
            t => t.key,
            t => t.value);

    CreateTable(name, fields);
}

这样,您仍然可以使用特定类型、泛型方式调用它,或者您可以通过简单地传递类型对象从循环中调用它。


话虽如此,如果您无法更改方法以获取 Type 对象,那么您需要使用反射来调用它:

var m = GetType().GetMethod("CreateTables").MakeGenericMethod(new Type[] { type });
m.Invoke(this, null);

注意!这假设您只有一种这样的方法可用,它是公开的,等等。

【讨论】:

  • 我也用另一种类似的方法编辑了这个问题,它也适合这种情况吗?确实会非常有用
  • @MandarJogalekar 是的,对此答案的最后一句话是我对您对我的答案的评论的评论。只需通过反射创建一个泛型方法并调用它
【解决方案2】:

你可以做这样的事情:

public void CreateTables<T>()
{
  CreateTables(typeof(T));
}

public void CreateTables(Type type)
{
  string name = type.Name;

  var fields = type.GetProperties().Select(
      t => new { 
         key = t.Name.ToLower(CultureInfo.InvariantCulture), 
         value = SqLiteUtility.GetSQLiteTypeString(t.PropertyType) 
      }).ToDictionary(
         t => t.key, 
         t => t.value);

  CreateTable(name, fields);
}

然后:

Type[] types=new Types[]{typeof(Class1),typeof(Class2)}

foreach(var type in types)
{
    CreateTables(type);
}

如果您在循环中使用该方法,则可以删除通用版本,根本不需要它

【讨论】:

  • 当然有效。还有另一种方法(已编辑的原始问题),不确定是否适合此方法,但答案很好:)
  • 您可以使用反射来创建通用方法定义并调用它。相当丑陋,但它的工作原理
【解决方案3】:

试试这个:

public void CreateTables<T>() => CreateTables(typeof(T));

public void CreateTables(Type type)
{        
    string name = type.Name;

    var fields = type.GetProperties()
      .Select(t => new { 
          key = t.Name.ToLower(CultureInfo.InvariantCulture), 
          value = SqLiteUtility.GetSQLiteTypeString(t.PropertyType) })
      .ToDictionary(t => t.key, t => t.value);

    CreateTable(name, fields);
 }

甚至这个:

public void CreateTables(IEnumerable<Type> types) {
    if(types != null) {
        foreach(Type type in types) {
            CreateTables(type);
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 2020-04-21
    • 1970-01-01
    • 1970-01-01
    • 2020-11-21
    相关资源
    最近更新 更多