2011-02-08 63 views
129

me gustaría tener acceso al valor de un dynamic C# propiedad con una cadena:Obtener valor de propiedad dinámica C# a través de la cadena

dynamic d = new { value1 = "some", value2 = "random", value3 = "value" };

¿Cómo puedo obtener el valor de d.value2 ("al azar ") si solo tengo" value2 "como una cadena? En javascript, podría hacer d ["value2"] para acceder al valor ("random"), pero no estoy seguro de cómo hacer esto con C# y reflection. Lo más cerca que he venido es esto:

d.GetType().GetProperty("value2") ... pero no sé cómo obtener el valor real de eso.

Como siempre, gracias por su ayuda!

+17

Tenga en cuenta que este no es el propósito previsto de "dinámico" y que este escenario no funciona mejor con "dinámico" que con "objeto". "dinámico" hace que sea posible acceder a las propiedades cuando el * nombre * de la propiedad se conoce en tiempo de compilación, pero el * tipo * no lo es. Como no conoce ni el nombre ni el tipo en tiempo de compilación, la dinámica no lo ayudará. –

+0

Posiblemente relacionado: http://stackoverflow.com/questions/5877251/lookup-property-in-object-graph-via-a-string. – DuckMaestro

+0

@EricLippert Sé que esta pregunta es antigua, pero solo para hacer un comentario en caso de que alguien la vea en el futuro. En algunos casos, no puede elegir si usar dinámicos u objetos (por ejemplo, cuando usa el analizador JSON) y aún puede querer obtener las propiedades de una cadena (de un archivo de configuración, por ejemplo), por lo que este uso no es tan inusual como uno podría pensar inicialmente. – Pedrom

Respuesta

149

Una vez que tenga su PropertyInfo (de GetProperty), debe llamar al GetValue y pasar la instancia de la que desea obtener el valor. En su caso:

d.GetType().GetProperty("value2").GetValue(d, null); 
+4

obtengo un '' d.GetType(). GetProperty ("value2"). GetValue (d) 'lanzó una excepción de tipo' System.Reflection.TargetInvocationException '\t dynamic {System.Reflection.TargetInvocationException} 'en el ver la ventana con eso ...? – TimDog

+0

@TimDog: ¿Cuál es el mensaje de error en la excepción? –

+4

Think GetValue necesita un parámetro adicional, p. d.GetType(). GetProperty ("value2"). GetValue (d, null) – dommer

3

d.GetType().GetProperty("value2")

devuelve un objeto PropertyInfo.

Así pues, hacedlo

propertyInfo.GetValue(d) 
+0

gracias, esta fue la respuesta correcta, pero como se mencionó anteriormente, el 'GetValue (d)' debe ser 'GetValue (d, null)' – TimDog

20

Dynamitey es una biblioteca de código abierto .net std, que te permite llamar así la palabra clave dynamic, pero el uso de la cadena para el nombre de la propiedad en lugar de que el compilador lo hace por usted, y termina siendo equal to reflection speedwise (que no es tan rápido como el uso de la palabra clave dinámica, pero esto se debe a la sobrecarga adicional de almacenamiento en caché de forma dinámica, donde el compilador almacena en caché estáticamente).

Dynamic.InvokeGet(d,"value2"); 
34
public static object GetProperty(object target, string name) 
{ 
    var site = System.Runtime.CompilerServices.CallSite<Func<System.Runtime.CompilerServices.CallSite, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, name, target.GetType(), new[]{Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0,null)})); 
    return site.Target(site, target); 
} 

añadir una referencia a Microsoft.CSharp. Funciona también para tipos dinámicos y propiedades y campos privados.

Editar: Si bien este enfoque funciona, no hay casi 20 × método más rápido de la AsambleaMicrosoft.VisualBasic.dll:

public static object GetProperty(object target, string name) 
{ 
    return Microsoft.VisualBasic.CompilerServices.Versioned.CallByName(target, name, CallType.Get); 
} 
+1

Solo quería mencionar que la versión de VisualBasic no es equivalente a su versión original 'GetProperty' (el GetProperty en realidad invoca el GetMember dinámico, que funciona incluso en objetos Python en IronPython). – Trevor

+0

¿cuál sería el objetivo del objeto? – Demodave

+0

@Demodave El objeto sobre el que desea invocar la propiedad ('d' en la pregunta). – IllidanS4

7

Gran parte del tiempo cuando se pide un objeto dinámico, obtienes un ExpandoObject (no en el ejemplo anónimo de la pregunta, sino estáticamente en tipado, pero mencionas JavaScript y el analizador JSON elegido JsonFx, por ejemplo, genera ExpandoObjects).

Si su dinámica es de hecho un ExpandoObject, puede evitar la reflexión colocándola en IDictionary, como se describe en http://msdn.microsoft.com/en-gb/library/system.dynamic.expandoobject.aspx.

Una vez que haya echado a IDictionary, se tiene acceso a métodos útiles como .Item y .ContainsKey

+0

Desafortunadamente, tener que convertir a IDictionary y usar TryGetValue por ejemplo, hace que se devuelva un objeto simple. No puede aprovechar los operadores implícitos en ese punto, ya que solo se consideran en tiempo de compilación. Por ejemplo, si tuviera una clase Int64Proxy con conversión implícita a Int64 ?, entonces ¿Int64? i = data.value; // los datos son ExpandoObject' buscarían automáticamente y llamarían al operador implícito. Por otro lado, si tuviera que usar IDictionary para probar si el campo "valor" existe, obtendría un objeto que no se lanzaría sin error a Int64. – Triynko

3

Esta es la forma i que tenga el valor de un valor de propiedad de un dinámico:

public dynamic Post(dynamic value) 
    {    
     try 
     { 
      if (value != null) 
      { 
       var valorCampos = ""; 

       foreach (Newtonsoft.Json.Linq.JProperty item in value) 
       { 
        if (item.Name == "valorCampo")//property name 
         valorCampos = item.Value.ToString(); 
       }           

      } 
     } 
     catch (Exception ex) 
     { 

     } 


    } 
5

El método más fácil para obtener un setter y un getter para una propiedad que funcione para cualquier tipo, incluyendo dynamic y ExpandoObject, es usar FastMember, que también es el método más rápido (usa Emit).

Puede obtener un TypeAccessor basado en un tipo determinado o un ObjectAccessor basado en una instancia de un tipo determinado.

Ejemplo:

var staticData = new Test { Id = 1, Name = "France" }; 
var objAccessor = ObjectAccessor.Create(staticData); 
objAccessor["Id"].Should().Be(1); 
objAccessor["Name"].Should().Be("France"); 

var anonymous = new { Id = 2, Name = "Hilton" }; 
objAccessor = ObjectAccessor.Create(anonymous); 
objAccessor["Id"].Should().Be(2); 
objAccessor["Name"].Should().Be("Hilton"); 

dynamic expando = new ExpandoObject(); 
expando.Id = 3; 
expando.Name = "Monica"; 
objAccessor = ObjectAccessor.Create(expando); 
objAccessor["Id"].Should().Be(3); 
objAccessor["Name"].Should().Be("Monica"); 

var typeAccessor = TypeAccessor.Create(staticData.GetType()); 
typeAccessor[staticData, "Id"].Should().Be(1); 
typeAccessor[staticData, "Name"].Should().Be("France"); 

typeAccessor = TypeAccessor.Create(anonymous.GetType()); 
typeAccessor[anonymous, "Id"].Should().Be(2); 
typeAccessor[anonymous, "Name"].Should().Be("Hilton"); 

typeAccessor = TypeAccessor.Create(expando.GetType()); 
((int)typeAccessor[expando, "Id"]).Should().Be(3); 
((string)typeAccessor[expando, "Name"]).Should().Be("Monica"); 
1

El GetProperty/GetValue no funciona para los datos JSON, que siempre generan una excepción nula, sin embargo, puede intentar este enfoque:

Serialice su objeto utilizando JsonConvert:

var z = Newtonsoft.Json.JsonConvert.DeserializeObject(Convert.ToString(request)); 

luego acceder a ella directamente fundición de nuevo a cadena:

var pn = (string)z["DynamicFieldName"]; 

Puede funcionar correctamente aplicando Convert.ToString (solicitud) ["DynamicFieldName"], pero no lo he probado.

+0

Este método genera el error: error CS0021: No se puede aplicar la indexación con [] a una expresión de tipo 'objeto'. Use 'new JavaScriptSerializer(). Deserialize (json);' para llegar a las "propiedades" en la forma en que sugirió –

Cuestiones relacionadas