2012-03-16 177 views
6

試圖創建一個微軟Office對象到POCO的一個映射,發現這個反思COM互操作對象

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

回答

17

在撰寫本文時的其他兩個答案都是正確的,但他們錯過了一個重要的機會來解釋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

1

您需要使用Type.InvokeMember(propertyName, BindingFlags.GetProperty, binder, target, args)名來指定他們,因爲沒有知道什麼性質的最近綁定對象的方式將有編譯時間。相反,您需要在運行時執行查找,通常是通過字符串比較。

RCW.GetProperties()只有在編譯時可以確定屬性及其位置時纔有效。