关于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()
才有效。