Posso alterar um campo de somente leitura em C # usando reflection?

Eu estou querendo saber, uma vez que muitas coisas podem ser feitas usando a reflection, posso alterar um campo readonly privado depois que o construtor concluiu sua execução?
(nota: apenas curiosidade)

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 

Você pode:

 typeof(Foo) .GetField("bar",BindingFlags.Instance|BindingFlags.NonPublic) .SetValue(foo,567); 

O óbvio é tentar:

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

Isso funciona bem. (Java tem regras diferentes, curiosamente – você tem que definir explicitamente o Field para ser acessível, e ele só funcionará para campos de instância de qualquer maneira).

Eu concordo com as outras respostas em que ele funciona de forma geral e especialmente com o comentário de E. Lippert de que isso não é um comportamento documentado e, portanto, não um código à prova de futuro.

No entanto, também notamos outro problema. Se você estiver executando seu código em um ambiente com permissions restritas, poderá receber uma exceção.

Acabamos de ter um caso em que nosso código funcionou bem em nossas máquinas, mas recebemos uma VerificationException quando o código foi executado em um ambiente restrito. O culpado foi uma chamada de reflection para o levantador de um campo de leitura. Funcionou quando removemos a restrição de leitura desse campo.

Você perguntou por que você iria querer quebrar o encapsulamento assim.

Eu uso uma class auxiliar de entidade para hidratar entidades. Isso usa a reflection para obter todas as propriedades de uma nova entidade vazia e faz a correspondência do nome da propriedade / campo com a coluna no conjunto de resultados e o define usando propertyinfo.setvalue ().

Não quero que ninguém mais possa alterar o valor, mas também não quero me esforçar para usar methods de hidratação de código personalizados para cada entidade.

Meus muitos procs armazenados retornam conjuntos de resultados que não correspondem diretamente a tabelas ou visualizações, portanto, o código gen ORM não faz nada para mim.

A resposta é sim, mas mais importante:

Por que você iria querer? Quebrar intencionalmente o encapsulamento parece uma idéia terrivelmente ruim para mim.

Usar a reflection para mudar um campo readonly ou constante é como combinar a Lei das Conseqüências Não-Intencionais com a Lei de Murphy .

Não faça isso.

Eu passei um dia consertando um bug surreal em que objects não podiam ser do tipo declarado.

Modificando o campo readonly funcionou uma vez. Mas se você tentasse modificá-lo novamente, você teria situações como esta:

 SoundDef mySound = Reflection_Modified_Readonly_SoundDef_Field; if( !(mySound is SoundDef) ) Log("Welcome to impossible-land!"); //This would run 

Então não faça isso.

Isso foi no tempo de execução Mono (mecanismo de jogo Unity).

Outra maneira simples de fazer isso usando inseguro (ou você poderia passar o campo para um método C via DLLImport e defini-lo lá).

 using System; namespace TestReadOnly { class Program { private readonly int i; public Program() { i = 66; } private unsafe void ForceSet() { fixed (int* ptr = &i) *ptr = 123; } static void Main(string[] args) { var program = new Program(); Console.WriteLine("Contructed Value: " + program.i); program.ForceSet(); Console.WriteLine("Forced Value: " + program.i); } } } 

Eu só quero acrescentar que se você precisa fazer isso para testes unitários, então você pode usar:

A) A class PrivateObject

B) Você ainda precisará de uma instância PrivateObject, mas você pode gerar objects “Accessor” com o Visual Studio. Como: Regenerar os Acessores Privados

Se você estiver definindo campos privados de um object em seu código fora do teste de unidade, isso seria uma instância de “código de cheiro”. Acho que talvez a única outra razão pela qual você gostaria de fazer isso seja se estiver lidando com um terceiro. biblioteca e você não pode alterar o código da class de destino. Mesmo assim, você provavelmente quer entrar em contato com a terceira parte, explicar sua situação e ver se eles não vão em frente e mudar o código para acomodar sua necessidade.