2012-03-16 21 views
6

Tratando de crear un asignador para un objeto de Microsoft Office en Poco de y encontramos estaReflexión sobre la interoperabilidad COM objetos

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

por lo que tienen que recurrir a este

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

que funciona por ahora, pero se preguntaba por qué el RCW.GetProperties() no funciona aquí?

Respuesta

17

Las otras dos respuestas a partir de este escrito son correctas, pero pierden una oportunidad importante para explicar cómo se ve el enlace tardío de un objeto COM en términos del sistema de tipo .NET. Cuando llama al GetType en el objeto COM, el valor devuelto es el tipo interno __ComObject, no el tipo de interfaz COM con la que normalmente trabaja cuando escribe el código de interoperabilidad. Puede ver esto en el depurador o con algún código como Console.WriteLine(o.GetType().Name);.

El tipo __ComObject no tiene propiedades; es por eso que obtienes una matriz vacía cuando llamas al o.GetType().GetProperties(). (¡Al menos algunas cosas en la vida tienen sentido!)

Si descompila el método InvokeMember, encontrará que tiene un manejo especial para los objetos COM, delegando la llamada a un método nativo interno. Para los objetos .NET "regulares", el método utiliza la reflexión .NET "normal", recuperando el MemberInfo apropiado para el miembro solicitado e invocando el mismo.

Usted puede utilice .NET reflejo en la interfaz tipo. Por ejemplo, si sabe que el objeto es un Excel Worksheet, puede usar typeof(Worksheet).GetProperties() y usar las instancias PropertyInfo resultantes con su objeto. Sin embargo, si no conoce el tipo de objeto en tiempo de compilación, debe llamar al GetType(), como en su código de ejemplo. En ese caso, tiene que usar InvokeMember.

1

Es necesario especificar por su nombre utilizando Type.InvokeMember(propertyName, BindingFlags.GetProperty, binder, target, args) porque no hay forma de saber qué propiedades de un objeto unido últimamente voluntad tener en tiempo de compilación. En cambio, debe realizar esa búsqueda en el tiempo de ejecución, generalmente a través de la comparación de cadenas.

RCW.GetProperties() solo funcionaría si pudiera determinar las propiedades y sus ubicaciones en tiempo de compilación.

Cuestiones relacionadas