2011-12-25 30 views
54

Supongamos que tengo una variable dinámica (reflexión?):Obtener valor de la propiedad de C# objeto dinámico por la cadena

dynamic d = *something* 

Ahora, algo crea propiedades a d la que tengo en el otro lado de una cuerda matriz:

string[] strarray = { 'property1','property2',..... } 

No sé los nombres de las propiedades con antelación.

Como en el código, una vez que se crea d y strArray se extrae de DB, puedo obtener los valores?

quiero conseguir d.property1 , d.property2.

veo que el objeto tiene un diccionario interno _dictionary que contiene las claves y los valores, cómo los recupero?

+1

¿Es 'algo' un' IDynamicMetaObjectProvider'? – SLaks

+0

Compruebe el tipo de tiempo de ejecución de 'something' en el depurador y observe sus miembros públicos. – SLaks

+1

¿Puedes verificar qué proporciona 'd.GetType()' en tiempo de ejecución? –

Respuesta

77

No sé si hay una forma más elegante con objetos creados de forma dinámica, pero utilizando la reflexión simple y llano debería funcionar:

var nameOfProperty = "property1"; 
var propertyInfo = myObject.GetType().GetProperty(nameOfProperty); 
var value = propertyInfo.GetValue(myObject, null); 

GetProperty volverá null si el tipo de myObject no contiene una propiedad pública con este nombre


EDITAR: Si el objeto no es un objeto "regular" pero algo implementar IDynamicMetaObjectProvider, este enfoque no funciona. Por favor, eche un vistazo a esta pregunta en su lugar:

+0

Por desgracia, no funciona: object obj = serializer.Deserialize(json, typeof(object)); var propertyInfo = obj.GetType().GetProperty("H3"); var value = propertyInfo.GetValue(obj, null); PropertyInfo es nulo, la tercera línea de una excepción . –

+0

@ sergata.NETLTD: ¿Pero 'var value = obj.H3' funcionaría? ¿Puedes verificar eso? – Heinzi

+0

sí, funcionaría. Esto funciona: dynamic obj = serializer.Deserialize (json, typeof (object)); var value = obj.H3; valor contiene el valor correcto. El problema es: no sé que H3 es un nombre de propiedad por adelantado. Los nombres de propiedad provienen del DB. Gracias por su ayuda. –

17

Esto le dará todos los nombres de propiedades y valores definidos en la variable dinámica.

dynamic d = { // your code }; 
object o = d; 
string[] propertyNames = o.GetType().GetProperties().Select(p => p.Name).ToArray(); 
foreach (var prop in propertyNames) 
{ 
    object propValue = o.GetType().GetProperty(prop).GetValue(o, null); 
} 
+1

Esto funcionó muy bien para mí, lo que no pude lograr para el tipo dinámico, gracias –

+0

Eso solo funciona si d es de tipo estático. Si D es IDynamicMetaObjectProvider, (como JObject) le dará las propiedades incorrectas. Por ejemplo, si d = obj, no devolverá 'x', devolverá las propiedades sin procesar en JObject. JObject obj = JObject.FromObject (nuevo { x = 123 }); –

5
string json = w.JSON; 

var serializer = new JavaScriptSerializer(); 
serializer.RegisterConverters(new[] { new DynamicJsonConverter() }); 

DynamicJsonConverter.DynamicJsonObject obj = 
     (DynamicJsonConverter.DynamicJsonObject)serializer.Deserialize(json, typeof(object)); 

Ahora obj._Dictionary contiene un diccionario. ¡Perfecto!

Este código debe ser utilizado en conjunción con Deserialize JSON into C# dynamic object? + crea la variable _dictionary de "sólo lectura privada" al público en el código no

18

la esperanza que esto ayudaría a que:

public static object GetProperty(object o, string member) 
{ 
    if(o == null) throw new ArgumentNullException("o"); 
    if(member == null) throw new ArgumentNullException("member"); 
    Type scope = o.GetType(); 
    IDynamicMetaObjectProvider provider = o as IDynamicMetaObjectProvider; 
    if(provider != null) 
    { 
     ParameterExpression param = Expression.Parameter(typeof(object)); 
     DynamicMetaObject mobj = provider.GetMetaObject(param); 
     GetMemberBinder binder = (GetMemberBinder)Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, member, scope, new CSharpArgumentInfo[]{CSharpArgumentInfo.Create(0, null)}); 
     DynamicMetaObject ret = mobj.BindGetMember(binder); 
     BlockExpression final = Expression.Block(
      Expression.Label(CallSiteBinder.UpdateLabel), 
      ret.Expression 
     ); 
     LambdaExpression lambda = Expression.Lambda(final, param); 
     Delegate del = lambda.Compile(); 
     return del.DynamicInvoke(o); 
    }else{ 
     return o.GetType().GetProperty(member, BindingFlags.Public | BindingFlags.Instance).GetValue(o, null); 
    } 
} 
+0

¿Puedes explicar este código? – Ewerton

+0

@Ewerton Ha pasado bastante tiempo, pero veo que usa * System.Linq.Expressions * para vincular el captador dinámico a un sitio de llamada y deja la compilación en * LambdaExpression *. No sé si tomé esto de un código descompilado, o en otro lugar. – IllidanS4

2

¿Te ha ver ExpandoObject clase?

Directamente desde MSDN description: "representa un objeto cuyos miembros se pueden añadir de forma dinámica y eliminado en tiempo de ejecución."

Con él se puede escribir código como este:

Pensamiento
dynamic employee = new ExpandoObject(); 
employee.Name = "John Smith"; 
((IDictionary<String, Object>)employee).Remove("Name"); 
+0

No se conocen los nombres de las propiedades, así que esto no funcionará. – user3285954

+0

El código funciona (lo comprobé en Visual Studio) porque la instancia del empleado es un ExpandoObject, por lo que es posible agregar y eliminar propiedades en tiempo de ejecución (cómo se explica en la documentación oficial de MS). Este código cumple la pregunta. – ADIMO

0

esto podría ayudar a alguien en el futuro.

Si conoce el nombre de la propiedad ya, usted puede hacer algo como lo siguiente:

[HttpPost] 
[Route("myRoute")] 
public object SomeApiControllerMethod([FromBody] dynamic args){ 
    var stringValue = args.MyPropertyName.ToString(); 
    //do something with the string value. If this is an int, we can int.Parse it, or if it's a string, we can just use it directly. 
    //some more code here.... 
    return stringValue; 
} 
+0

No se conocen los nombres de las propiedades. – user3285954

0

si D fue creado por Newtonsoft puede utilizar esto para leer los nombres y valores de la propiedad:

foreach (JProperty property in d) 
    { 
     DoSomething(property.Name, property.Value); 
    } 
Cuestiones relacionadas