c# - tiempo - ¿Cómo puedo llamar dinámicamente un método en un objeto dinámico?
objetos dinamicos c# (2)
Cuando quiero llamar dinámicamente un método definido estáticamente ("estáticamente" en el sentido de "determinado en tiempo de compilación", no en el sentido de "miembro de nivel de clase") en cualquier objeto en C #, puedo usar la reflexión obtener un identificador de ese método e invocarlo:
typeof(Foo).GetMethod("Bar").Invoke(foo, new object[] { /* params */ });
Sin embargo, los objetos dinámicos al DynamicObject
de DynamicObject
responden a llamadas de métodos de instancia (no definidas) usando TryInvokeMember
, y los métodos dinámicos a los que responde la clase no están expuestos a través de la reflexión, por razones obvias. Esto significa que no puedo obtener un identificador de método para un método al que TryInvokeMember
debe responder.
Así que, irónicamente, me parece que no puede llamar dinámicamente un método dinámico en un objeto dynamic
tan fácilmente como puede llamar un método definido en un objeto no dynamic
.
He considerado llamar a TryInvokeMember
directamente, pero el primer argumento debe ser una instancia de InvokeMemberBinder
, una clase abstracta. Siento que si tengo que implementar una clase para llamar a un método dinámico en un objeto dinámico, debo estar haciendo algo mal.
¿Cómo puedo llamar a un método en un objeto dynamic
por su nombre, sabiendo que la clase de destino no lo implementa y que se debe responder utilizando TryInvokeMember
?
Tengo un framework de código abierto (licencia de Apache) Dynamitey (disponible en nuget) que encapsula el código de enlace dinámico, esto incluye el almacenamiento automático en caché de los sitios de llamadas. También tiene métodos de conveniencia para cada tipo de carpeta (captadores, configuradores, eventos, indexadores, operadores, conversiones), pero específicamente desea InvokeMember .
El código de enlace dinámico en realidad se ejecuta más rápido que la reflexión (amortizado) al llamar a miembros de clases definidas estáticamente (en el momento de la compilación).
Dynamic.InvokeMember(foo,"Bar",arg...);
Una forma de hacerlo es imitar lo que el compilador de C # genera para las invocaciones de métodos en objetos dinámicos. Esto requiere el uso de un montón de tipos marcados [EditorBrowsable(EditorBrowsableState.Never)]
en el espacio de nombres Microsoft.CSharp.RuntimeBinder
, por lo que no serán visibles en Intellisense. No hace falta decir que esto no parece ser un escenario compatible, ¡así que úselo bajo su propio riesgo!
Este código llama al método de la Bar
dinámica sin ningún argumento en una instancia de una clase derivada de DynamicObject
:
dynamic dynamicObject = new DerivedFromDynamicObject();
var callSiteBinder = Binder.InvokeMember(CSharpBinderFlags.None, "Bar", Enumerable.Empty<Type>(), typeof(Program),
new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
var callSite = CallSite<Action<CallSite, object>>.Create(callSiteBinder);
callSite.Target(callSite, dynamicObject);
This publicación de blog y esta tienen más detalles sangrientos sobre los sitios de llamadas y las carpetas.