2009-03-06 19 views
243

¿Hay alguna manera en C# 3.5 donde puedo usar la reflexión para establecer una propiedad del objeto?Establezca la propiedad del objeto usando la reflexión

Ex:

MyObject obj = new MyObject(); 
obj.Name = "Value"; 

Quiero establecer obj.Name con la reflexión. Algo como:

Reflection.SetProperty(obj, "Name") = "Value"; 

¿Hay alguna manera de hacer esto?

Respuesta

297

Sí, puede utilizar Type.InvokeMember():

using System.Reflection; 
MyObject obj = new MyObject(); 
obj.GetType().InvokeMember("Name", 
    BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty, 
    Type.DefaultBinder, obj, "Value"); 

Esto lanzará una excepción si obj no tiene una propiedad llamada Name, o no se puede establecer.

Otro enfoque es obtener los metadatos de la propiedad y luego configurarlo. Esto le permitirá comprobar la existencia de la propiedad, y verificar que se puede configurar:

using System.Reflection; 
MyObject obj = new MyObject(); 
PropertyInfo prop = obj.GetType().GetProperty("Name", BindingFlags.Public | BindingFlags.Instance); 
if(null != prop && prop.CanWrite) 
{ 
    prop.SetValue(obj, "Value", null); 
} 
+55

Si no se trata con todas las cadenas Es posible que desee convertir los datos en primer lugar: 'var = val Convert.ChangeType (propValue, propInfo.PropertyType);' fuente: http://www.devx.com/vb2themax/Tip/19599 – LostNomad311

+2

alternativamente, yo u puede usar 'obj.GetType(). GetProperty ("Nombre") ?. GetSetMethod() ?. Invoke (...)' – tecfield

227

También puede hacer:

Type type = target.GetType(); 

PropertyInfo prop = type.GetProperty("propertyName"); 

prop.SetValue (target, propertyValue, null); 

donde destino es el objeto que va a tener la propiedad conjunto.

+10

he hecho esta misma cosa hoy. Lo anterior funciona muy bien, obviamente se debe hacer una comprobación nula en el accesorio antes de intentar usarlo. –

+4

+1 ¡Para un código más limpio! – Sham

+3

@AntonyScott yo creo que te gustaría saber si está invocando la propiedad equivocada, por lo que "error de forma silenciosa" parece una mala supuesto. –

11

También puede acceder a los campos usando de manera simillar:

var obj=new MyObject(); 
FieldInfo fi = obj.GetType(). 
    GetField("Name", BindingFlags.NonPublic | BindingFlags.Instance); 
fi.SetValue(obj,value) 

Con la reflexión todo puede ser un libro abierto :) En mi ejemplo estamos unión a un campo de instancia privada.

76

Reflexión, básicamente, es decir

myObject.GetType().GetProperty(property).SetValue(myObject, "Bob", null); 

o hay bibliotecas que ayudan tanto en términos de conveniencia y rendimiento; por ejemplo, con FastMember:

var wrapped = ObjectAccessor.Create(obj); 
wrapped[property] = "Bob"; 

(que también tiene la ventaja de no tener que saber de antemano si se trata de un campo frente a una propiedad)

+0

¡Guau, me confundí un poco de la fusión, pero encontré tu respuesta otra vez! Gracias, que se merece una 'aceptar', pero dado que se fusiona mi hilo :(Gracias de nuevo! –

+0

@Bob lo siento por cualquier confusión –

+0

1 para la solución de una sola línea. Funcionaba como encanto. Gracias Marc. – pordi

13

Sí, utilizando System.Reflection:

using System.Reflection; 

... 

    string prop = "name"; 
    PropertyInfo pi = myObject.GetType().GetProperty(prop); 
    pi.SetValue(myObject, "Bob", null); 
21

O podría envolver el único forro de Marc dentro de su propia clase de extensión:

public static class PropertyExtension{  

    public static void SetPropertyValue(this object obj, string propName, object value) 
    { 
     obj.GetType().GetProperty(propName).SetValue(obj, value, null); 
    } 
} 

y lo llaman así:

myObject.SetPropertyValue("myProperty", "myValue"); 

Por si fuera poco, vamos a añadir un método para obtener un valor de propiedad:

public static object GetPropertyValue(this object obj, string propName) 
{ 
     return obj.GetType().GetProperty(propName).GetValue (obj, null); 
} 
7

Puede probar esto cuando desee propiedades de masa-asignar de una objeto de otro objeto utilizando nombres de propiedad:

public static void Assign(this object destination, object source) 
    { 
     if (destination is IEnumerable && source is IEnumerable) 
     { 
      var dest_enumerator = (destination as IEnumerable).GetEnumerator(); 
      var src_enumerator = (source as IEnumerable).GetEnumerator(); 
      while (dest_enumerator.MoveNext() && src_enumerator.MoveNext()) 
       dest_enumerator.Current.Assign(src_enumerator.Current); 
     } 
     else 
     { 
      var destProperties = destination.GetType().GetProperties(); 
      foreach (var sourceProperty in source.GetType().GetProperties()) 
      { 
       foreach (var destProperty in destProperties) 
       { 
        if (destProperty.Name == sourceProperty.Name && destProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType)) 
        { 
         destProperty.SetValue(destination,  sourceProperty.GetValue(source, new object[] { }), new object[] { }); 
         break; 
      } 
     } 
    } 
} 
+2

Hola y bienvenidos a desbordamiento de pila. por favor, formatee su código correctamente y no solo lo descargue en su publicación, ayudará a otros a entender su respuesta. – ThreeFx

8

Use somethings como este:

public static class PropertyExtension{  

    public static void SetPropertyValue(this object p_object, string p_propertyName, object value) 
    { 
    PropertyInfo property = p_object.GetType().GetProperty(p_propertyName); 
    property.SetValue(p_object, Convert.ChangeType(value, property.PropertyType), null); 
    } 
} 

o

public static class PropertyExtension{  

    public static void SetPropertyValue(this object p_object, string p_propertyName, object value) 
    { 
    PropertyInfo property = p_object.GetType().GetProperty(p_propertyName); 
    Type t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType; 
    object safeValue = (value == null) ? null : Convert.ChangeType(value, t); 

    property.SetValue(p_object, safeValue, null); 
    } 
} 
+1

La parte donde obtienes el tipo de propiedad y luego la echaste fue realmente útil para mí. Funciona a las mil maravillas. Gracias – Marc

0

simplemente he publicado un paquete Nuget que permite la creación de no sólo las primeras propiedades de nivel pero propiedades también anidados en el objeto dado en cualquier profundidad.

Aquí es the package

establece el valor de una propiedad de un objeto por su camino desde la raíz.

El objeto puede ser un objeto complejo y la propiedad puede ser propiedad anidada profunda de niveles múltiples o puede ser una propiedad directamente debajo de la raíz. ObjectWriter encontrará la propiedad usando el parámetro ruta de propiedad y actualizará su valor. La ruta de la propiedad es el nombre adjunto de las propiedades visitadas desde la raíz hasta la propiedad del nodo final que queremos establecer, delimitada por el parámetro de la cadena del delimitador.

Uso:

Para configurar las propiedades directamente en la raíz del objeto:

Ie. LineItem clase tiene una propiedad llamada int ItemId

LineItem lineItem = new LineItem(); 

ObjectWriter.Set(lineItem, "ItemId", 13, delimiter: null); 

Para la creación de la propiedad anidada múltiples niveles por debajo de la raíz del objeto:

Ie. Invite clase tiene una propiedad llamada State, que tiene una propiedad llamada Invite (de Invitar tipo), que tiene una propiedad llamada Recipient, que tiene una propiedad llamada Id.

Para hacer las cosas aún más complejas, la propiedad State no es un tipo de referencia, es un struct.

Aquí es cómo se puede establecer la propiedad Id (a valor de cadena de “perspectiva”) en la parte inferior del árbol de objetos en una sola línea.

Invite invite = new Invite(); 

ObjectWriter.Set(invite, "State_Invite_Recipient_Id", "outlook", delimiter: "_"); 
0

Sobre la base de la sugerencia de MarcGravell, he construido el siguiente método estático method.The genéricamente asigna todas las propiedades de coincidencia de objeto de origen a destino mediante FastMember

public static void DynamicPropertySet(object source, object target) 
    { 
     //SOURCE 
     var src_accessor = TypeAccessor.Create(source.GetType()); 
     if (src_accessor == null) 
     { 
      throw new ApplicationException("Could not create accessor!"); 
     } 
     var src_members = src_accessor.GetMembers(); 
     if (src_members == null) 
     { 
      throw new ApplicationException("Could not fetch members!"); 
     } 
     var src_class_members = src_members.Where(x => x.Type.IsClass && !x.Type.IsPrimitive); 
     var src_class_propNames = src_class_members.Select(x => x.Name); 
     var src_propNames = src_members.Except(src_class_members).Select(x => x.Name); 

     //TARGET 
     var trg_accessor = TypeAccessor.Create(target.GetType()); 
     if (trg_accessor == null) 
     { 
      throw new ApplicationException("Could not create accessor!"); 
     } 
     var trg_members = trg_accessor.GetMembers(); 
     if (trg_members == null) 
     { 
      throw new ApplicationException("Could not create accessor!"); 
     } 
     var trg_class_members = trg_members.Where(x => x.Type.IsClass && !x.Type.IsPrimitive); 
     var trg_class_propNames = trg_class_members.Select(x => x.Name); 
     var trg_propNames = trg_members.Except(trg_class_members).Select(x => x.Name); 



     var class_propNames = trg_class_propNames.Intersect(src_class_propNames); 
     var propNames = trg_propNames.Intersect(src_propNames); 

     foreach (var propName in propNames) 
     { 
      trg_accessor[target, propName] = src_accessor[source, propName]; 
     } 
     foreach (var member in class_propNames) 
     { 
      var src = src_accessor[source, member]; 
      var trg = trg_accessor[target, member]; 
      if (src != null && trg != null) 
      { 
       DynamicPropertySet(src, trg); 
      } 
     } 
    } 
Cuestiones relacionadas