Изменение свойств только для чтения с отражением - PullRequest
21 голосов
/ 14 сентября 2010

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

Ответы [ 5 ]

18 голосов
/ 14 сентября 2010

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

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

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

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

16 голосов
/ 09 августа 2015

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

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, возможно, вам придется изменить часть кода для работы.Наслаждайтесь! </p>

12 голосов
/ 01 декабря 2016

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

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

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

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

var field = typeof(MyClass).GetField("<MyNumber>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic);
field.SetValue(anIstanceOfMyClass, 3);
0 голосов
/ 14 сентября 2010
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);
0 голосов
/ 14 сентября 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...