反射和泛型类型

12

我正在编写一些代码用于类构造函数,该函数循环遍历类的所有属性并调用一个通用静态方法,该方法使用来自外部API的数据填充我的类。因此,我有一个示例类:

public class MyClass{
  public string Property1 { get; set; }
  public int Property2 { get; set; }
  public bool Property3 { get; set; }

  public static T DoStuff<T>(string name){
    // get the data for the property from the external API
    // or if there's a problem return 'default(T)'
  }
}

现在在我的构造函数中,我希望有这样的东西:

public MyClass(){
  var properties = this.GetType().GetProperties();
  foreach(PropertyInfo p in properties){
    p.SetValue(this, DoStuff(p.Name), new object[0]);
  }
}

因为我没有提供泛型类型,所以上述构造函数将会抛出错误。

那么如何传入属性的类型呢?


抱歉,这个问题有点令人困惑,第二段代码片段中是否有一些拼写错误? - smaclell
是的,我认为你想写的应该是"MyClass.DoStuff(p.Name)"作为p.SetValue()的第二个参数。 - Matt Hamilton
是的,我在第二个代码片段中犯了一个错误。 - Aaron Powell
可能是重复的问题:如何使用反射调用通用方法? - nawfal
3个回答

19

您想使用每个属性的类型作为T来调用DoStuff<T>吗?在这种情况下,您需要使用反射和MakeGenericMethod - 即

var properties = this.GetType().GetProperties();
foreach (PropertyInfo p in properties)
{
    object value = typeof(MyClass)
    .GetMethod("DoStuff")
    .MakeGenericMethod(p.PropertyType)
    .Invoke(null, new object[] { p.Name });
    p.SetValue(this, value, null);
}

然而,这并不是很美观。实际上,我想是否只有以下方式会更好:

static object DoStuff(string name, Type propertyType);
... and then
object value = DoStuff(p.Name, p.PropertyType);

在这个例子中,泛型会给你什么?请注意,在反射调用期间,值类型仍将被装箱等操作-即使在这种情况下,装箱并不像你想象的那样糟糕
最后,在许多场景中,TypeDescriptor.GetProperties()比Type.GetProperties()更合适-可以实现灵活的对象模型等。

7

你的构造函数代码是否应该像这样:

public MyClass(){
  var properties = this.GetType().GetProperties();
  foreach(PropertyInfo p in properties){
    p.SetValue(this, DoStuff(p.Name), new object[0]);
  }
}

请注意使用DoStuff而不是MyClass

如果是这样,问题在于您试图在不适用的情况下使用泛型。泛型的一个(好)用途是使用编译时类型安全性。在这里,您在编译时不知道类型!您可以通过反射调用该方法(获取打开的形式,然后调用MakeGenericMethod),但这相当丑陋。

DoStuff真的需要是泛型的吗?它是否从其他地方使用?PropertyInfo.SetValue的参数只是对象,因此即使您可以以通用方式调用该方法,仍将获得装箱等。


2
如果您不在其他地方使用DoStuff方法,我建议您编写一个非泛型方法。也许您创建泛型方法是为了能够使用default(T)。要在非泛型方法中替换它,您可以对于值类型使用Activator.CreateInstance(T),对于引用类型使用null:
object defaultResult = type.IsValueType ? Activator.CreateInstance(type) : null

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接