Изменение свойств только для чтения с отражением
Возможно ли это? С отражением или любым другим способом?
Ответы
Ответ 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);