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?
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
.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With