no estoy seguro si hay cualquier método en el marco que en realidad devuelve un GetMemberBinder
, pero no importa - que no es la forma correcta para invocar un miembro dinámico por su nombre.
Lo que realmente necesita hacer es crear un sitio de llamadas. El método es el siguiente:
static object GetDynamicMember(object obj, string memberName)
{
var binder = Binder.GetMember(CSharpBinderFlags.None, memberName, obj.GetType(),
new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
var callsite = CallSite<Func<CallSite, object, object>>.Create(binder);
return callsite.Target(callsite, obj);
}
Tenga en cuenta que Binder.GetMember
crea una CallSiteBinder
, no un GetMemberBinder
. Solo para ser 100% claro. Este método generará un RuntimeBinderException
si falla la llamada interna al TryGetMember
, por lo que no es necesario que verifique el resultado. Si no desea que las personas que llaman vean el RuntimeBinderException
, envuélvalo en su propio try/catch.
El envío dinámico es complejo, al menos en relación con la reflexión sobre tipos estáticos. Como el CLR no se escribe de manera dinámica, C# tiene que crear una instancia de un compilador para averiguar cómo ejecutar el miembro/método. Eso es crear un sitio de llamadas. Por lo que yo sé, usted tiene para hacer esto, razón por la cual cada método Binder
devuelve CallSiteBinder
y no puede instanciar ninguno de los encuadernadores directamente.
Tenga en cuenta que el DLR realiza algún tipo de almacenamiento en caché de sitios de llamadas, pero no estoy seguro de si el almacenamiento en caché automático cubre este escenario. Es muy probable que desee guardar su sitio de llamadas para futuras llamadas para evitar la sobrecarga de la recopilación constante.
P.S. Si está utilizando (o puede usar) ExpandoObject
en lugar de DynamicObject
, tenga en cuenta que implementa IDictionary<string, object>
, por lo que no necesita hacer nada de esto. Simplemente transfiéralo al tipo de diccionario y verifica si la propiedad existe. Solo usaría DynamicObject
en ExpandoObject
si estuviera haciendo algo mucho más complicado que simplemente agregar miembros en tiempo de ejecución, es decir, cambiar el comportamiento real en función del encuadernador de tiempo de ejecución.
Me falta algo ... ¿no es exactamente todo este método lo que el operador de asignación dinámica ya hace, excepto que es menos confiable? – Aaronaught
Mi pregunta es acerca de obtener un valor de campo de un objeto dinámico sin saber a la vez cómo se llama ese campo. Por lo tanto, no puedo codificar, por ejemplo, "var MyValue = TheDynamicObject.TheField;" porque solo en tiempo de ejecución se obtiene el nombre del campo. Estoy escribiendo una clase de propósito general para tratar con objetos dinámicos provistos externamente. –