COM互操作对象的反思

10

尝试为 Microsoft Office 对象创建映射器到 POCO's,发现了这个:

// doesn't work
// returns an empty array where o is a RCW on an office object
foreach(var pi in  o.GetType().GetProperties() ) 
    tgt.SetValue(rc, pi.GetValue(o, null));

所以不得不采取这种方法

foreach(var field in tgt.GetFields() ){
    var pv = o.InvokeMember(field.Name, System.Reflection.BindingFlags.GetProperty, null, o, null);
    i.SetValue(rc, pv);
}

这个方法暂时可用,但不知道为什么这里不能使用 RCW.GetProperties() 方法?

3个回答

20
截至本文撰写时,其他两个答案是正确的,但它们忽略了一个重要的机会来解释COM对象的后期绑定在.NET类型系统中的表现方式。当您在COM对象上调用GetType时,返回值是__ComObject内部类型,而不是编写互操作代码时通常使用的COM接口类型。您可以在调试器中或通过一些代码(例如Console.WriteLine(o.GetType().Name);)中看到这一点。 __ComObject类型没有属性; 这就是为什么在调用o.GetType().GetProperties()时会得到空数组的原因。(至少生活中有些事情是有意义的!)
如果反汇编InvokeMember方法,则会发现它具有针对COM对象的特殊处理,将调用委托给内部本机方法。对于“常规”的.NET对象,该方法使用“常规”的.NET反射,检索所请求成员的适当MemberInfo并调用它。
您可以在接口类型上使用.NET反射。例如,如果您知道对象是Excel Worksheet,则可以使用typeof(Worksheet).GetProperties(),并使用结果的PropertyInfo实例。如果您不知道对象的类型,需要在运行时调用GetType(),就像您的示例代码一样。在这种情况下,您需要使用InvokeMember

4

2
你需要通过名称使用 Type.InvokeMember(propertyName, BindingFlags.GetProperty, binder, target, args) 来指定它们,因为在编译时无法知道最近绑定对象将具有哪些属性。相反,您需要在运行时执行该查找,通常是通过字符串比较来完成。 RCW.GetProperties() 只能在编译时确定属性及其位置才能起作用。

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