关于COM Interop对象的思考

尝试为POCO创建一个Microsoft Office对象的映射器并找到它

// 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()在这里不起作用?

在撰写本文时,另外两个答案是正确的,但是他们错过了一个重要的机会来解释COM对象的后期绑定如何看起来与.NET类型系统有关。 在COM对象上调用GetType时,返回值是__ComObject内部类型,而不是编写互操作代码时通常使用的COM接口类型。 您可以在调试器中看到这个,或者使用一些代码,如Console.WriteLine(o.GetType().Name);

__ComObject类型没有属性; 这就是你调用o.GetType().GetProperties()时得到一个空数组的原因。 (至少生活中的一些事情是有意义的!)

如果您反编译InvokeMember方法,您会发现它对COM对象有特殊处理,将调用委托给内部本机方法。 对于“常规”.NET对象,该方法使用“常规”.NETreflection,检索所请求成员的相应MemberInfo并调用它。

可以接口类型上使用.NETreflection。 例如,如果您知道该对象是Excel Worksheet ,则可以使用typeof(Worksheet).GetProperties() ,并将结果PropertyInfo实例与您的对象一起使用。 但是,如果在编译时不知道对象的类型,则需要调用GetType() ,如示例代码中所示。 在这种情况下,您仍然坚持使用InvokeMember

这是因为COM对象最近被绑定了。 在访问/调用COM对象之前,运行时不知道哪些方法/属性可用。

这里有一些关于这个主题的好文章:

http://support.microsoft.com/default.aspx?scid=kb;en-us;Q302902

http://www.codeproject.com/Articles/10838/How-To-Get-Properties-and-Methods-in-Late-Binding

您需要使用Type.InvokeMember(propertyName, BindingFlags.GetProperty, binder, target, args)按名称指定它们,因为无法知道最新绑定对象在编译时将具有哪些属性。 相反,您需要在运行时执行该查找,通常是通过字符串比较。

只有在编译时可以确定属性及其位置时, RCW.GetProperties()才有效。