Establecer la propiedad del objeto mediante reflexión


¿Hay alguna forma en C# 3.5 en la que pueda usar reflexión para establecer una propiedad de objeto?

Ex:

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

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

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

¿Hay alguna manera de hacer esto?

Author: jpaugh, 2009-03-06

11 answers

Sí, puedes usar Type.InvokeMember():

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

Esto producirá 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 establecerlos. Esto le permitirá comprobar la existencia de la propiedad, y verificar que puede ser:

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);
}
 327
Author: Andy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-09 20:22:06

También puedes hacer:

Type type = target.GetType();

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

prop.SetValue (target, propertyValue, null);

Donde target es el objeto que tendrá su propiedad establecida.

 246
Author: El Cheicon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-06 17:55:33

Reflexión, básicamente, es decir,

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

O hay bibliotecas para ayudar tanto en términos de conveniencia como de rendimiento; por ejemplo con FastMember :

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

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

 79
Author: Marc Gravell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-20 14:05:09

O podrías envolver un forro de Marc dentro de tu 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 llámalo así:

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

Para una buena medida, vamos a agregar 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);
}
 23
Author: Erik K.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-20 21:44:05

Sí, usando System.Reflection:

using System.Reflection;

...

    string prop = "name";
    PropertyInfo pi = myObject.GetType().GetProperty(prop);
    pi.SetValue(myObject, "Bob", null);
 14
Author: D Stanley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-21 13:49:35

También puede acceder a los campos usando una manera similar:

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

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

 11
Author: JoshBerke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-06 18:00:20

Use algo como esto:

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);
   }
}
 10
Author: Ardalan Shahgholi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-03 10:11:01

Puede probar esto cuando desee asignar en masa propiedades de un Objeto desde 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;
            }
        }
    }
}
 7
Author: user3679106,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-20 18:35:41

Acabo de publicar un paquete Nuget que permite configurar no solo las Propiedades de primer nivel, sino también las propiedades anidadas en el objeto dado en cualquier profundidad.

Aquí está el paquete

Establece el valor de una propiedad de un objeto por su ruta desde la raíz.

El objeto puede ser un objeto complejo y la propiedad puede ser una propiedad anidada profunda de varios niveles o puede ser una propiedad directamente debajo de la raíz. ObjectWriter encontrará la propiedad usando la propiedad parámetro path y actualizar su valor. Property path son los nombres adjuntos de las propiedades visitadas desde la raíz hasta la propiedad del nodo final que queremos establecer, delimitadas por el parámetro delimiter string.

Uso:

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

Ie. LineItem la clase tiene una propiedad int llamada ItemId

LineItem lineItem = new LineItem();

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

Para configurar propiedades anidadas en varios niveles debajo de la raíz del objeto:

Ie. Invite la 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 puede establecer la propiedad Id (al valor de cadena de "outlook") 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
Author: Dogu Arslan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-24 18:25:15

Basado en la sugerencia de MarcGravell, he construido el siguiente método estático.El método genéricamente asigna todas las propiedades coincidentes del objeto de origen al objetivo usando 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);
            }
        }
    }
 0
Author: Cogent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-15 15:06:03

Puedo establecer la propiedad class usando reflection donde las propiedades de mi clase son solo una cadena. Ahora tengo que introducir un diccionario como miembro de esa clase pero no puedo establecer el valor. Estoy usando el siguiente fragmento de código para las propiedades de cadena.

object objval;
objval=System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(className);
objval.GetType().GetProperty(classpropertyname).SetValue(objval,Value);

Cómo establecer el valor del diccionario usando reflexión

 0
Author: Abhishek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-20 05:50:36