Ответ 1
Вы можете:
typeof(Foo)
.GetField("bar",BindingFlags.Instance|BindingFlags.NonPublic)
.SetValue(foo,567);
Мне интересно, так как многое можно сделать с помощью отражения, могу ли я изменить личное поле readonly после того, как конструктор завершил выполнение?
(обратите внимание: просто любопытство)
public class Foo
{
private readonly int bar;
public Foo(int num)
{
bar = num;
}
public int GetBar()
{
return bar;
}
}
Foo foo = new Foo(123);
Console.WriteLine(foo.GetBar()); // display 123
// reflection code here...
Console.WriteLine(foo.GetBar()); // display 456
Вы можете:
typeof(Foo)
.GetField("bar",BindingFlags.Instance|BindingFlags.NonPublic)
.SetValue(foo,567);
Очевидная вещь - попробовать:
using System;
using System.Reflection;
public class Test
{
private readonly string foo = "Foo";
public static void Main()
{
Test test = new Test();
FieldInfo field = typeof(Test).GetField
("foo", BindingFlags.Instance | BindingFlags.NonPublic);
field.SetValue(test, "Hello");
Console.WriteLine(test.foo);
}
}
Это прекрасно работает. (Java имеет разные правила, интересно - вам нужно явно установить Field
, чтобы он был доступен, и он будет работать только для полей экземпляра.)
Я согласен с другими ответами в том, что он работает в целом и особенно с комментарием Э. Липперта, что это не документированное поведение и, следовательно, не будущий код.
Однако мы также заметили еще одну проблему. Если вы используете свой код в среде с ограниченными разрешениями, вы можете получить исключение.
У нас только что был случай, когда наш код отлично работал на наших машинах, но мы получили VerificationException
, когда код работал в ограниченной среде. Преступник был рефлекторным призывом к установщику поля readonly. Он работал, когда мы удалили ограничение только на чтение этого поля.
Вы спросили, почему вы хотели бы разбить такую инкапсуляцию.
Я использую класс вспомогательной сущности для гидратации сущностей. Это использует отражение для получения всех свойств нового пустого объекта и сопоставляет имя свойства/поля с столбцом в наборе результатов и устанавливает его с помощью propertyinfo.setvalue().
Я не хочу, чтобы кто-либо еще мог изменить значение, но я не хочу прикладывать все усилия к настраиваемым методам гидратации кода для каждого объекта.
Многие мои сохраненные procs возвращают результаты, которые не соответствуют непосредственно таблицам или представлениям, поэтому код GEN ORM ничего не делает для меня.
Ответ: да, но что более важно:
Зачем вам это нужно? Умышленное нарушение инкапсуляции кажется для меня ужасно плохой идеей.
Использование отражения для изменения поля readonly или constant похоже на объединение Закона о непредвиденных последствиях с Закон Мерфи.
Не делайте этого.
Я просто провел день, фиксируя сюрреалистическую ошибку, где объекты могут быть не из своего объявленного типа.
Изменение поля readonly, выполненного один раз. Но если вы попытаетесь изменить его снова, вы получите такие ситуации:
SoundDef mySound = Reflection_Modified_Readonly_SoundDef_Field;
if( !(mySound is SoundDef) )
Log("Welcome to impossible-land!"); //This would run
Так что не делай этого.
Это было в режиме исполнения Mono (движок игры Unity).
Я просто хочу добавить, что если вам нужно сделать это для модульного тестирования, вы можете использовать:
A) PrivateObject класс
B) Вам все равно понадобится экземпляр PrivateObject, но вы можете создавать объекты "Accessor" с помощью Visual Studio. Практическое руководство. Регенерация частных аксессуаров
Если вы устанавливаете частные поля объекта в своем коде вне модульного тестирования, это будет экземпляр "запаха кода", я думаю, что, возможно, единственная причина, по которой вы хотели бы это сделать, - это иметь дело с сторонняя библиотека, и вы не можете изменить код целевого класса. Даже тогда вы, вероятно, захотите связаться со сторонней стороной, объяснить свою ситуацию и посмотреть, не будут ли они идти дальше и изменить свой код, чтобы удовлетворить ваши потребности.