关于组件模型和反射技术

4

我有一个可以接受任何对象的函数,然后从其属性或字段中获取输入值。

目前它的代码如下:

private string GetFieldValue(object o, Field f)
{
 //field.name is name of property or field
        MemberInfo[] mi = o.GetType().GetMember(field.name, MemberTypes.Field | MemberTypes.Property,
            BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | 
            BindingFlags.ExactBinding );

        if (mi.Length == 0) throw new ArgumentException("Field", "Can't find member: " + f.name);

        Object value;
        if (mi[0].MemberType == MemberTypes.Property)
             value = ((PropertyInfo)mi[0]).GetValue(o, null);
        else value = ((FieldInfo)mi[0]).GetValue(o);

今天我阅读了关于System.ComponentModel及其XXXDescriptor类的内容。在性能方面,使用反射和ComponentModel这两个框架有何区别?如果使用ComponentModel重写上述内容,是否可以实现更好的性能或灵活性?我所知道的这两者之间唯一的其他区别是ComponentModel支持虚拟属性。谢谢。
2个回答

6
区别在于ComponentModel是对原始类的抽象。这意味着您可以定义不存在的属性,实际上,这正是 / 将列公开为数据绑定属性的方式。使用ComponentModel,即使在1.1中,您也可以获得类似“动态”的东西。
您可能认为这意味着ComponentModel速度较慢;但实际上,您可以利用此抽象来获得收益... HyperDescriptor正是这样做的-使用编写直接IL来表示属性,比反射或香草ComponentModel都要快得多。
但请注意,默认情况下,ComponentModel仅限于属性(而不是字段)。您可以通过即时门面来执行此操作,但这不是一个好主意。在ComponentModel中也没有太多地方适合“只写”属性。

3

TypeDescriptor(位于System.ComponentModel中)具有内部缓存,因此可以获得更好的性能,但这并不妨碍您向上述代码添加缓存。 TypeDescriptor使用反射,虽然它允许您扩展对象并添加不受“真实”属性和事件支持的属性和事件,但不支持字段。

如果我是您,并且不关心TypeDescriptor的可扩展性特性,并且愿意在GetMember之上添加自己的缓存,则应坚持使用反射。

编辑:标准反射自2.0以来已经缓存了MemberInfo对象-请参见MSDN“ 使用.NET:避免常见性能陷阱以加快应用程序速度”


TypeDescriptor并没有比标准反射做更多的缓存 - 主要瓶颈是invoke,无论哪种方式都很慢。但请参见我的回复,了解如何改进此问题(使用围绕ComponentModel的自定义)。 - Marc Gravell
我一直认为TypeDescriptor是被缓存的(TypeDescriptor类的MSDN页面上有“属性和事件由TypeDescriptor缓存以提高速度”),而反射则解析程序集元数据。 - Tim Robinson
反射不是已经缓存了MemberInfo吗? 来自MSDN的说明:“在.NET Framework 2.0中,MemberInfo缓存是惰性填充的,这意味着工作集成本更低,检索方法所需的时间更少。如果您知道要获取的特定方法的名称,请使用非复数的GetXX方法。” - majkinetor
我选择了非复数版本。第一个解决方案是遍历所有成员并查看我需要什么,但由于上述引用而放弃了这种方法,转而采用非复数方法。 - majkinetor
谢谢你的缓存提示 - 我在从1.1转换到2.0时可能错过了它! - Tim Robinson

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