Изменение свойств только для чтения с отражением

Возможно ли это? С отражением или любым другим способом?

Ответы

Ответ 1

Как указано в других случаях, если вам нужно это сделать, перед вами стоит проблема с дизайном. Теперь, если вы хотите знать, возможно ли это только ради знания, или если нет другого способа сделать это, это действительно возможно, с помощью очень маленького вспомогательная библиотека и метод расширения.

Рассмотрим следующий код:

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");

Используя этот код, вы можете получить поле поддержки свойства только с помощью свойства и назначить новое значение для поля поддержки. Вы можете прочитать более подробную информацию о реализация.

Также обратите внимание, что он работает только для простых свойств, таких как:

public int Age { get { return age; } }

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

public double Velocity { get; private set; }

Если у вас есть сложные свойства с настраиваемым кодом, то распознаватель поля поддержки будет терпеть неудачу.

Ответ 2

Как очень грязный обход для автоматически генерируемых свойств только для чтения:

class MyTestClass
{
    public string MyProperty { get; }

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

Вы можете изменить автоматически созданное поле поддержки следующим образом:

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" );

PS: когда вы используете .NET-версию < 4.6, возможно, вам придется изменить часть кода для работы. Наслаждайтесь!

Ответ 3

Альтернативный ответ Саймона Мэтта будет

Предполагая, что у вас есть:

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

Вы можете сделать это, если это для цели тестирования:

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

Ответ 4

это зависит от свойства. если это вычисленное свойство - нет, если вы не знаете, на чем оно основано. если это просто аксессор в частном поле, то вы можете попытаться изменить поле.

в целом, однако, это очень плохая идея, поскольку вы, вероятно, не знаете, какие побочные эффекты это вызовет.

Ответ 5

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);