Отражение на объектах COM Interop - PullRequest
6 голосов
/ 16 марта 2012

Попытка создать сопоставитель для объекта Microsoft Office для POCO и обнаружила это

// 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() здесь не работает?

Ответы [ 3 ]

17 голосов
/ 24 марта 2012

Два других ответа на момент написания статьи верны, но они упускают важную возможность объяснить, как выглядит поздняя привязка COM-объекта с точки зрения системы типов .NET. Когда вы вызываете GetType для COM-объекта, возвращаемое значение имеет внутренний тип __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.

4 голосов
/ 21 марта 2012

Это потому, что 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

2 голосов
/ 22 марта 2012

Вам нужно указать их по имени, используя Type.InvokeMember(propertyName, BindingFlags.GetProperty, binder, target, args), потому что нет способа узнать, какими свойствами будет обладать объект, привязанный к последним, во время компиляции. Вместо этого вам нужно выполнить этот поиск во время выполнения, обычно с помощью сравнения строк.

RCW.GetProperties() будет работать, только если вы сможете определить свойства и их расположение во время компиляции.

...