Reflection on COM Interop objects

China☆狼群 提交于 2020-01-22 20:02:26

问题


Trying to create a mapper for an Microsoft Office object to POCO's and found this

// 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));

so have to resort to this

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

which works for now but wondering why the RCW.GetProperties() doesn't work here?


回答1:


The other two answers as of this writing are correct, but they miss an important opportunity to explain how the late binding of a COM object looks in terms of the .NET type system. When you call GetType on the COM object, the return value is the __ComObject internal type, not the COM interface type that you normally work with when writing interop code. You can see this in the debugger, or with some code like Console.WriteLine(o.GetType().Name);.

The __ComObject type has no properties; that's why you get an empty array when you call o.GetType().GetProperties(). (At least some things in life make sense!)

If you decompile the InvokeMember method, you'll find that it has special handling for COM objects, delegating the call to an internal native method. For "regular" .NET objects, the method uses "regular" .NET reflection, retrieving the appropriate MemberInfo for the requested member, and invoking it.

You can use .NET reflection on the interface type. For example, if you know that the object is an Excel Worksheet, you can use typeof(Worksheet).GetProperties(), and use the resulting PropertyInfo instances with your object. If you don't know the type of the object at compile time, however, you need to call GetType(), as in your example code. In that case, you're stuck with using InvokeMember.




回答2:


It is because the COM object is lately bound. The run time does not know what methods/properties will be available on a COM object until they are accessed/invoked.

Here are some good articles on the subject:

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




回答3:


You need to specify them by name using Type.InvokeMember(propertyName, BindingFlags.GetProperty, binder, target, args) because there's no way of knowing what properties a lately-bound object will have at compile-time. Instead, you need to perform that lookup at runtime, usually via string comparison.

RCW.GetProperties() would only work if you could determine the properties and their locations at compile-time.



来源:https://stackoverflow.com/questions/9735394/reflection-on-com-interop-objects

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!