【问题标题】:Reflection and generic types反射和泛型类型
【发布时间】:2008-10-13 07:37:22
【问题描述】:

我正在为类构造函数编写一些代码,该构造函数循环遍历类的所有属性并调用通用静态方法,该方法使用来自外部 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]);
  }
}

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

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

【问题讨论】:

  • 对不起,这个问题有点混乱,第二个代码 sn-p 有错别字吗?
  • 是的,我想你的意思是写“MyClass.DoStuff(p.Name)”作为 p.SetValue() 的第二个参数。
  • 是的,我在第二个代码 sn-p 中犯了一个错误。

标签: c# .net generics reflection


【解决方案1】:

你想用 T = 每个属性的类型来调用 DoStuff 吗?在这种情况下,“原样”您将需要使用反射和 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);

在这个例子中泛型给了你什么?请注意,在反射调用期间,值类型仍会被装箱等 - 甚至会装箱 isn't as bad as you might think

最后,在许多情况下,TypeDescriptor.GetProperties() 比 Type.GetProperties() 更合适 - 允许灵活的对象模型等。

【讨论】:

    【解决方案2】:

    你的构造函数代码是这样写的吗:

    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 的参数只是对象,因此即使您可以一般地调用该方法,您仍然会得到装箱等。

    【讨论】:

      【解决方案3】:

      如果你不使用其他地方的DoStuff,我也建议编写一个非泛型方法。

      也许您创建了能够使用 default(T) 的通用方法。要在非泛型方法中替换它,您可以将 Activator.CreateInstance(T) 用于值类型,将 null 用于引用类型:

      object defaultResult = type.IsValueType ? Activator.CreateInstance(type) : null
      

      【讨论】:

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