Réflexion sur les objects COM Interop

Essayer de créer un mappeur pour un object Microsoft Office avec POCO et j’ai trouvé ceci

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

alors faut recourir à cette

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

qui fonctionne pour l’instant mais vous vous demandez pourquoi RCW.GetProperties() ne fonctionne pas ici?

Les deux autres réponses au moment de la rédaction de cet article sont correctes, mais elles manquent une occasion importante d’expliquer à quoi ressemble la liaison tardive d’un object COM en termes de système de type .NET. Lorsque vous appelez GetType sur l’object COM, la valeur de retour est le type interne __ComObject , et non le type d’interface COM avec lequel vous travaillez normalement lors de l’écriture de code interop. Vous pouvez le voir dans le débogueur ou avec du code tel que Console.WriteLine(o.GetType().Name); .

Le type __ComObject n’a pas de propriétés. c’est pourquoi vous obtenez un tableau vide lorsque vous appelez o.GetType().GetProperties() . (Au moins certaines choses dans la vie ont un sens!)

Si vous décomstackz la méthode InvokeMember , vous constaterez qu’elle dispose d’un traitement spécial pour les objects COM, en déléguant l’appel à une méthode native interne. Pour les objects .NET “normaux”, la méthode utilise une reflection .NET “normale”, en récupérant le MemberInfo approprié pour le membre demandé et en l’ MemberInfo .

Vous pouvez utiliser la reflection .NET sur le type d’ interface . Par exemple, si vous savez que l’object est une Worksheet Excel, vous pouvez utiliser typeof(Worksheet).GetProperties() et utiliser les instances PropertyInfo obtenues avec votre object. Si vous ne connaissez pas le type de l’object au moment de la compilation, vous devez appeler GetType() , comme dans votre exemple de code. Dans ce cas, vous êtes coincé avec InvokeMember .

C’est parce que l’object COM est lié récemment. Le moteur d’exécution ne sait pas quelles méthodes / propriétés seront disponibles sur un object COM jusqu’à ce qu’elles soient accédées / invoquées.

Voici quelques bons articles sur le sujet:

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

Vous devez les spécifier par leur nom à l’aide de Type.InvokeMember(propertyName, BindingFlags.GetProperty, binder, target, args) car il est impossible de savoir quelles propriétés un object récemment lié aura lors de la compilation. Au lieu de cela, vous devez effectuer cette recherche au moment de l’exécution, généralement via une comparaison de chaînes.

RCW.GetProperties() ne fonctionnerait que si vous pouviez déterminer les propriétés et leurs emplacements au moment de la compilation.