2010-09-14 13 views
15

¿Es posible? Con reflexión o de otra manera?Cambio de propiedades de solo lectura con reflexión

+5

Élodie: Es posible, pero * * ¡NO LO HAGAS **! – Gabe

+0

¿Está tratando de cambiar el valor de retorno de una propiedad con getter solamente, o el valor de un campo de respaldo que es de solo lectura (como 'private readonly int primitiveValue = 1;')? – Elisha

+0

Hola Élodie, ¿podrías solicitar más información o aceptar una respuesta? –

Respuesta

13

Como dice otro, si necesita hacer eso, se enfrenta a un problema de diseño para empezar. Ahora, si quiere saber si es posible por el solo hecho de saberlo, o si no hay otra manera en la tierra para hacerlo, de hecho es posible, con la ayuda de un muy pequeño helper library y un método de extensión.

Considere el siguiente código:

class Person { 

    int age; 
    string name; 

    public int Age { get { return age; } } 
    public string Name { get { return name; } } 
} 

// ... 

using Mono.Reflection; 
using System.Reflection; 

// ... 

Person person = new Person (27, "jb"); 
PropertyInfo nameProperty = typeof (Person).GetProperty ("Name"); 
FieldInfo nameField = nameProperty.GetBackingField(); 
nameField.SetValue (person, "jbe"); 

Usando este código, se puede obtener el respaldo de campo de una propiedad con sólo la propiedad, y asignar un nuevo valor al campo de respaldo. Puede leer más detalles sobre implementation.

También tenga en cuenta que sólo funciona para las propiedades simples, tales como:

public int Age { get { return age; } } 

public string Name { 
    get { return name; } 
    set { name = value; } 
} 

public double Velocity { get; private set; } 

Si tiene propiedades complejas con código personalizado, el sistema de resolución de campo respaldo fallará.

0

depende de la propiedad. si se trata de una propiedad calculada, no, a menos que sepa en qué se basa. si solo es un acceso a un campo privado, entonces puede intentar modificar el campo.

en general, sin embargo, es una muy mala idea, ya que es probable que no tenga conocimiento de los efectos secundarios que esto ocasionará.

0
PropertyInfo isReadOnly = typeof(System.Collections.Specialized.NameValueCollection).GetProperty("IsReadOnly", BindingFlags.Instance| BindingFlags.NonPublic); 
//Remove the readonly property 
isReadOnly.SetValue(param, false, null); 

//.............put your code here..... 

// Set readonly property 
isReadOnly.SetValue(param, true, null); 
9

Como una solución muy sucio para auto genera sólo lectura propiedades:

class MyTestClass 
{ 
    public string MyProperty { get; } 

    public MyTestClass(string MyProperty) 
    { 
     this.MyProperty = MyProperty; 
    } 
} 

Puede modificar el automático genera el campo respaldo de la siguiente manera:

MyTestClass MyClass = new MyTestClass("Hello"); 
FieldInfo MyWriteableField = MyClass.GetType().GetRuntimeFields().Where(a => Regex.IsMatch(a.Name, $"\\A<{nameof(MyClass.MyProperty)}>k__BackingField\\Z")).FirstOrDefault(); 
MyWriteableField.SetValue(MyClass, "Another new value"); 

PD: cuando están utilizando una .NET versión < 4.6 es posible que tenga que cambiar parte del código para que funcione. ¡Disfrútalo!

7

Una alternativa a la respuesta Simon Mattes sería

Suponiendo que tienen:

public class MyClass 
{ 
    public int MyNumber {get;} 
} 

Usted puede hacer esto si es para el propósito de la prueba:

var field = typeof(MyClass).GetField("<MyNumber>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic); 
field.SetValue(anIstanceOfMyClass, 3); 
Cuestiones relacionadas