Puedo establecer una propiedad privada a través de la reflexión?

public abstract class Entity
{
    private int _id;
    private DateTime? _createdOn;
    public virtual T Id
    {
        get { return _id; }
        private set { ChangePropertyAndNotify(ref _id, value, x => Id); }
    }
    public virtual DateTime? CreatedOn
    {
        get { return _createdOn; }
        private set { ChangePropertyAndNotify(ref _createdOn, value, x => CreatedOn); }
    }
}

He probado lo siguiente y no funciona, donde t representa un tipo de Entity:

var t = typeof(Entity);
var mi = t.GetMethod("set_CreatedOn", BindingFlags.Instance | BindingFlags.NonPublic);

Supongo que me puede hacer esto, pero no puedo trabajar fuera.

  • Sé que es tarde, pero he encontrado una necesidad de este pensamiento que me gustaría compartir mis «por qué». Yo necesitaba para superar un inconveniente en algún software de terceros. Específicamente, yo estaba usando el de Crystal Reports ExportToStream método. La manera en que este método fue escrito, el acceso a la corriente interna del búfer no estaba permitido. Con el fin de enviar el informe para el navegador, he tenido que copiar la secuencia en un nuevo buffer (100K+), y luego enviar hacia fuera. Por la configuración de la privada ‘_exposable campo en el objeto stream a ‘true’, que fue capaz de enviar el buffer interno, directamente, el ahorro de 100K+ asignación en cada solicitud.
  • Por qué? Digamos que usted ha privado de incubadoras en su Identificación de propiedades en toda su objeto de dominio y desea implementar el repositorio de pruebas. A continuación, sólo en su repositorio proyecto de prueba usted querrá ser capaz de establecer la propiedad Id.
  • Otro escenario de uso: configuración de auto-generado campos como la «fecha de creación», cuando la importación de datos.
InformationsquelleAutor AwkwardCoder | 2009-10-14

5 Comentarios

  1. 80
    t.GetProperty("CreatedOn")
        .SetValue(obj, new DateTime(2009, 10, 14), null);

    EDIT: Ya que la propiedad en sí es público, que al parecer no es necesario utilizar BindingFlags.NonPublic para encontrarlo. Llamar SetValue a pesar de que el setter tener menos de accesibilidad todavía hace lo que usted espera.

    • ¿A qué te refieres? Destapé LINQPad y esta probado y funcionó…
    • Para ser justos, depende del nivel de confianza, pero la respuesta parece válida.
    • Método set de propiedad no se encuentra en el Sistema.Reflexión.RuntimePropertyInfo.SetValue(Object obj, Objetos de valor, BindingFlags invokeAttr cuaderno Cuaderno, Object[] índice, CultureInfo cultura)
    • Esto funciona bien para mí, si yo no soy de usar una propiedad virtual. Si me SetValue con una propiedad virtual, esto no parece funcionar.
  2. 103

    Sí, es:

    ///<summary>
    ///Returns a _private_ Property Value from a given Object. Uses Reflection.
    ///Throws a ArgumentOutOfRangeException if the Property is not found.
    ///</summary>
    ///<typeparam name="T">Type of the Property</typeparam>
    ///<param name="obj">Object from where the Property Value is returned</param>
    ///<param name="propName">Propertyname as string.</param>
    ///<returns>PropertyValue</returns>
    public static T GetPrivatePropertyValue<T>(this object obj, string propName)
    {
    if (obj == null) throw new ArgumentNullException("obj");
    PropertyInfo pi = obj.GetType().GetProperty(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
    if (pi == null) throw new ArgumentOutOfRangeException("propName", string.Format("Property {0} was not found in Type {1}", propName, obj.GetType().FullName));
    return (T)pi.GetValue(obj, null);
    }
    ///<summary>
    ///Returns a private Property Value from a given Object. Uses Reflection.
    ///Throws a ArgumentOutOfRangeException if the Property is not found.
    ///</summary>
    ///<typeparam name="T">Type of the Property</typeparam>
    ///<param name="obj">Object from where the Property Value is returned</param>
    ///<param name="propName">Propertyname as string.</param>
    ///<returns>PropertyValue</returns>
    public static T GetPrivateFieldValue<T>(this object obj, string propName)
    {
    if (obj == null) throw new ArgumentNullException("obj");
    Type t = obj.GetType();
    FieldInfo fi = null;
    while (fi == null && t != null)
    {
    fi = t.GetField(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
    t = t.BaseType;
    }
    if (fi == null) throw new ArgumentOutOfRangeException("propName", string.Format("Field {0} was not found in Type {1}", propName, obj.GetType().FullName));
    return (T)fi.GetValue(obj);
    }
    ///<summary>
    ///Sets a _private_ Property Value from a given Object. Uses Reflection.
    ///Throws a ArgumentOutOfRangeException if the Property is not found.
    ///</summary>
    ///<typeparam name="T">Type of the Property</typeparam>
    ///<param name="obj">Object from where the Property Value is set</param>
    ///<param name="propName">Propertyname as string.</param>
    ///<param name="val">Value to set.</param>
    ///<returns>PropertyValue</returns>
    public static void SetPrivatePropertyValue<T>(this object obj, string propName, T val)
    {
    Type t = obj.GetType();
    if (t.GetProperty(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) == null)
    throw new ArgumentOutOfRangeException("propName", string.Format("Property {0} was not found in Type {1}", propName, obj.GetType().FullName));
    t.InvokeMember(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty | BindingFlags.Instance, null, obj, new object[] { val });
    }
    ///<summary>
    ///Set a private Property Value on a given Object. Uses Reflection.
    ///</summary>
    ///<typeparam name="T">Type of the Property</typeparam>
    ///<param name="obj">Object from where the Property Value is returned</param>
    ///<param name="propName">Propertyname as string.</param>
    ///<param name="val">the value to set</param>
    ///<exception cref="ArgumentOutOfRangeException">if the Property is not found</exception>
    public static void SetPrivateFieldValue<T>(this object obj, string propName, T val)
    {
    if (obj == null) throw new ArgumentNullException("obj");
    Type t = obj.GetType();
    FieldInfo fi = null;
    while (fi == null && t != null)
    {
    fi = t.GetField(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
    t = t.BaseType;
    }
    if (fi == null) throw new ArgumentOutOfRangeException("propName", string.Format("Field {0} was not found in Type {1}", propName, obj.GetType().FullName));
    fi.SetValue(obj, val);
    }
  3. 7

    Puede acceder privado setter de derivados de tipo de vía código

    public static void SetProperty(object instance, string propertyName, object newValue)
    {
    Type type = instance.GetType();
    PropertyInfo prop = type.BaseType.GetProperty(propertyName);
    prop.SetValue(instance, newValue, null);
    }
    • +1, Pero sólo una nota aquí. BaseType debe tener todas las propiedades que usted está esperando. Si usted está ocultando una propiedad (sin recordar lo que había hecho), que podría resultar en un poco de pelo arrancado.
  4. 3

    Ninguno de estos funcionó para mí, y mi nombre de la propiedad era única, así que sólo he usado este:

    public static void SetPrivatePropertyValue<T>(T obj, string propertyName, object newValue)
    {
    //add a check here that the object obj and propertyName string are not null
    foreach (FieldInfo fi in obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic))
    {
    if (fi.Name.ToLower().Contains(propertyName.ToLower()))
    {
    fi.SetValue(obj, newValue);
    break;
    }
    }
    }
  5. 0
        //mock class
    public class Person{
    public string Name{get; internal set;}
    }
    //works for all types, update private field through reflection
    public static T ReviveType<T>(T t, string propertyName, object newValue){
    //add a check here that the object t and propertyName string are not null
    PropertyInfo pi = t.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
    pi.SetValue(t, newValue, null); 
    return t;
    }
    //check the required function
    void Main()
    {
    var p = new Person(){Name="John"};
    Console.WriteLine("Name: {0}",p.Name);
    //box the person to object, just to see that the method never care about what type you pass it
    object o = p;
    var updatedPerson = ReviveType<Object>(o, "Name", "Webber") as Person;
    //check if it updated person instance
    Console.WriteLine("Name: {0}",updatedPerson.Name);
    }
    //Console Result: -------------------
    Name: John
    Name: Webber

Dejar respuesta

Please enter your comment!
Please enter your name here