2009-12-18 28 views
8

Sí, el título suena un poco confuso, entonces explicaré lo que quiero decir: supongamos que tiene un objeto 'dinámico' de C# 4.0 y el nombre de una propiedad. ¿Cómo recuperarías esa propiedad del objeto dinámico?Obteniendo un valor de un objeto dinámico dinámicamente

En otras palabras, ¿cómo poner en práctica:

public static object GetDynamicValue(dynamic o, string name) { ... } 

Otra manera de decirlo es que estoy tratando de tratar a un objeto dinámico como un IDictionary.

Tenga en cuenta que la reflexión probablemente no sea una opción aquí, ya que el objeto dinámico podría ser una implementación personalizada que no se basa en la reflexión (por ejemplo, ampliando DynamicObject y haciendo lo suyo).

+1

Se puede contar un poco más sobre su caso de uso? Si desea tener un objeto dinámico que sea similar a IDictionary, ¿por qué no usar ExpandoObject, por ejemplo? La sugerencia de Jon probablemente funcione, pero tengo la sensación de que esta es una solución demasiado complicada para lo que estás tratando de hacer. –

Respuesta

13

Usted tendría que construir un sitio de llamadas, crear una carpeta etc.

La forma más fácil de ver lo que sucede es compilar esto:

public static object GetDynamicValue(dynamic o, string name) 
{ 
    return o.Foo; 
} 

Entonces descompilar con reflector de resolver lo está haciendo. Sería bastante complicado, fíjate, y tendrás que cambiarlo de ser un sitio de llamada único, estático y en caché para crear uno nuevo en cada invocación.

Aquí hay un ejemplo que hace el trabajo ... pero si se trata de totalmente correcta o no es un asunto diferente :) (me esta pasando por hacer exactamente lo que he sugerido más arriba.)

using Microsoft.CSharp.RuntimeBinder; 
using System; 
using System.Dynamic; 
using System.Runtime.CompilerServices; 

class Test 
{ 
    public static object GetDynamicValue(dynamic o, string name) 
    { 
     CallSite<Func<CallSite, object, object>> site 
      = CallSite<Func<CallSite, object, object>>.Create 
      (Binder.GetMember(CSharpBinderFlags.None, name, 
      typeof(Test), new CSharpArgumentInfo[] 
      { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) })); 
     return site.Target(site, o); 
    } 

    static void Main() 
    { 
     Console.WriteLine(GetDynamicValue("hello", "Length")); 
    } 
} 
+0

Muy bien, gracias Jon! Eso trae muchos conceptos con los que no me he enfrentado, así que tendré que estudiarlos cuidadosamente. Parece extraño que se use typeof (Test) allí, ya que no debería ser relevante. Pero intenté configurarlo como nulo y el código sigue funcionando, así que aparentemente no estaba haciendo demasiado. –

+3

Es relevante en términos de qué miembros son accesibles: podrá obtener miembros privados de Test utilizando este código, pero no miembros privados de otros tipos. –

3

El El marco de código abierto ImpromptuInterface (disponible en nuget) hace esto y hace el trabajo extra involucrado porque el almacenamiento en caché del sitio de llamadas es importante para el rendimiento.

Ver InvokeGet

public static object GetDynamicValue(dynamic o, string name) { 
     return Impromptu.InvokeGet(o,name); 
} 
+0

Clay hace algo así también (http://clay.codeplex.com/) –

+0

@ David-Ebbo While Clay le permite acceder a sus propias propiedades a través del nombre de la cadena, 'InvokeGet' le permite acceder CUALQUIER propiedad IDynamicMetaObjectProvider a través del nombre de la cadena (o cualquier objeto regular más rápido que la reflexión) ... a menos que me falta algo. – jbtule

Cuestiones relacionadas