简体   繁体   English

反思和泛型类型

[英]Reflection and generic types

I'm writing some code for a class constructor which loops through all the properties of the class and calls a generic static method which populates my class with data from an external API. 我正在为类构造函数编写一些代码,它循环遍历类的所有属性,并调用一个通用的静态方法,该方法使用外部API中的数据填充我的类。 So I've got this as an example class: 所以我把它作为一个示例类:

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

Now in my constructor I want something like this: 现在在我的构造函数中我想要这样的东西:

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

So the above constructor will thrown an error because I'm not supplying the generic type. 所以上面的构造函数会抛出一个错误,因为我没有提供泛型类型。

So how do I pass in the type of the property in? 那么如何传入属性的类型呢?

Do you want to call DoStuff<T> with T = the type of each property? 你想用T =每个属性的类型调用DoStuff <T>吗? In which case, "as is" you would need to use reflection and MakeGenericMethod - ie 在这种情况下,“按原样”你需要使用反射和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);
}

However, this isn't very pretty. 但是,这不是很漂亮。 In reality I wonder if it wouldn't be better just to have: 实际上,我想知道如果不是更好的话:

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

What does the generics give you in this example? 在这个例子中,泛型给你什么? Note that value-types will still get boxed etc during the reflection call - and even then boxing isn't as bad as you might think . 请注意,在反射调用期间,值类型仍将被装箱等 - 甚至拳击也没有您想象的那么糟糕

Finally, in many scenarios, TypeDescriptor.GetProperties() is more appropriate than Type.GetProperties() - allows for flexible object models etc. 最后,在许多场景中,TypeDescriptor.GetProperties()比Type.GetProperties()更合适 - 允许灵活的对象模型等。

Was your constructor code meant to read like this: 您的构造函数代码是否意味着如下所示:

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

? Note the DoStuff instead of MyClass . 注意DoStuff而不是MyClass

If so, the problem is that you're trying to use generics when they're really not applicable. 如果是这样,那么问题在于,当它们真的不适用时,你会尝试使用泛型。 The point of generics (well, one of the points) is to use compile-time type safety. 泛型(点,其中一点)的用途是使用编译时类型安全性。 Here you don't know the type at compile time! 这里你不知道编译时的类型! You could call the method by reflection (fetching the open form and then calling MakeGenericMethod ) but that's pretty ugly. 你可以通过反射调用方法(获取打开的表单,然后调用MakeGenericMethod ),但这非常难看。

Does DoStuff really need to be generic in the first place? DoStuff真的需要首先是通用的吗? Is it being used from elsewhere? 它是从其他地方使用的吗? The parameter to PropertyInfo.SetValue is just object, so you'd still get boxing etc even if you could call the method generically. PropertyInfo.SetValue的参数只是对象,所以你仍然可以获得拳击等,即使你可以通常调用该方法。

If you don't use DoStuff from another place, I also suggest to write a non-generic method. 如果你不从其他地方使用DoStuff,我也建议你写一个非通用的方法。

Maybe you created the generic method to be able to use default(T). 也许您创建了通用方法以便能够使用默认值(T)。 To replace that in a non-generic method, you can use Activator.CreateInstance(T) for value types and null for reference types: 要在非泛型方法中替换它,可以对值类型使用Activator.CreateInstance(T),对引用类型使用null:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM