Мне интересно, так как многое можно сделать с помощью отражения, могу ли я изменить закрытое поле только для чтения после того, как конструктор завершил свое выполнение?
(примечание: просто любопытство)
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
c#
reflection
field
readonly
Рон Кляйн
источник
источник
Очевидное дело - попробовать:
Это прекрасно работает. (Интересно, что в Java действуют другие правила - вы должны явно указать
Field
доступность, и в любом случае это будет работать только для полей экземпляра.)источник
Я согласен с другими ответами в том, что он работает в целом и особенно с комментарием Э. Липперта о том, что это недокументированное поведение и, следовательно, не ориентированный на будущее код.
Однако мы заметили и другую проблему. Если вы запускаете свой код в среде с ограниченными разрешениями, вы можете получить исключение.
У нас только что был случай, когда наш код работал нормально на наших машинах, но мы получили,
VerificationException
когда код выполнялся в ограниченной среде. Виной всему был рефлексивный вызов установщика поля только для чтения. Это сработало, когда мы удалили ограничение только для чтения для этого поля.источник
Вы спросили, почему вы хотите нарушить такую инкапсуляцию.
Я использую вспомогательный класс сущностей для гидратации сущностей. Это использует отражение, чтобы получить все свойства новой пустой сущности, и сопоставляет имя свойства / поля со столбцом в наборе результатов и устанавливает его с помощью propertyinfo.setvalue ().
Я не хочу, чтобы кто-либо еще мог изменить значение, но я также не хочу тратить все силы на настраиваемые методы гидратации кода для каждой сущности.
Многие из моих сохраненных процедур возвращают наборы результатов, которые не соответствуют напрямую таблицам или представлениям, поэтому ORM кодового поколения ничего для меня не делают.
источник
Другой простой способ сделать это - использовать unsafe (или вы можете передать поле методу C через DLLImport и установить его там).
источник
Ответ положительный, но что более важно:
Зачем тебе это нужно? Намеренно нарушать инкапсуляцию мне кажется ужасно плохой идеей.
Использование отражения для изменения поля только для чтения или постоянного поля похоже на объединение Закона Непредвиденных Последствий с Законом Мерфи .
источник
Не делай этого.
Я просто потратил день на исправление сюрреалистической ошибки, из-за которой объекты могли не относиться к их собственному объявленному типу.
Изменение поля только для чтения сработало один раз. Но если вы попытаетесь изменить его снова, вы получите такие ситуации:
Так что не делай этого.
Это было в среде выполнения Mono (игровой движок Unity).
источник
Я просто хочу добавить, что если вам нужно сделать это для модульного тестирования, вы можете использовать:
A) PrivateObject класс
Б) Вам по-прежнему понадобится экземпляр PrivateObject, но вы можете сгенерировать объекты Accessor с помощью Visual Studio. Как: восстановить частные аксессоры
Если вы устанавливаете частные поля объекта в своем коде за пределами модульного тестирования, это будет примером «запаха кода». Я думаю, что, возможно, единственная другая причина, по которой вы захотите это сделать, - это если вы имеете дело с третьей стороной. библиотека, и вы не можете изменить код целевого класса. Даже в этом случае вы, вероятно, захотите связаться с третьим лицом, объяснить свою ситуацию и посмотреть, не пойдут ли они дальше и изменят свой код в соответствии с вашими потребностями.
источник