Me pregunto, dado que se pueden hacer muchas cosas mediante la reflexión, ¿puedo cambiar un campo privado de solo lectura después de que el constructor haya completado su ejecución?
(nota: solo curiosidad)
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
Ron Klein
fuente
fuente
Lo obvio es probarlo:
Esto funciona bien. (Java tiene reglas diferentes, curiosamente, debe establecer explícitamente
Field
que sea accesible, y de todos modos solo funcionará para campos de instancia).fuente
Estoy de acuerdo con las otras respuestas en que funciona en general y especialmente con el comentario de E. Lippert de que este no es un comportamiento documentado y, por lo tanto, no es un código a prueba de futuro.
Sin embargo, también notamos otro problema. Si está ejecutando su código en un entorno con permisos restringidos, es posible que obtenga una excepción.
Acabamos de tener un caso en el que nuestro código funcionó bien en nuestras máquinas, pero recibimos un mensaje
VerificationException
cuando el código se ejecutó en un entorno restringido. El culpable fue una llamada de reflexión al creador de un campo de solo lectura. Funcionó cuando eliminamos la restricción de solo lectura de ese campo.fuente
Preguntó por qué querría romper la encapsulación de esa manera.
Utilizo una clase auxiliar de entidad para hidratar entidades. Esto usa la reflexión para obtener todas las propiedades de una nueva entidad vacía, y hace coincidir el nombre de la propiedad / campo con la columna en el conjunto de resultados, y lo establece usando propertyinfo.setvalue ().
No quiero que nadie más pueda cambiar el valor, pero tampoco quiero hacer todo el esfuerzo para personalizar los métodos de hidratación del código para cada entidad.
Muchos de mis procesos almacenados devuelven conjuntos de resultados que no se corresponden directamente con tablas o vistas, por lo que los ORM de generación de código no hacen nada por mí.
fuente
Otra forma simple de hacer esto usando inseguro (o podría pasar el campo a un método C a través de DLLImport y configurarlo allí).
fuente
La respuesta es sí, pero lo más importante:
¿Por qué querrías hacerlo? Romper la encapsulación intencionalmente me parece una idea horriblemente mala.
Usar la reflexión para cambiar un campo de solo lectura o constante es como combinar la Ley de Consecuencias No Deseadas con la Ley de Murphy .
fuente
No hagas esto.
Acabo de pasar un día solucionando un error surrealista donde los objetos podrían no ser de su propio tipo declarado.
La modificación del campo de solo lectura funcionó una vez. Pero si intentara modificarlo nuevamente, obtendría situaciones como esta:
Así que no lo hagas.
Esto fue en el tiempo de ejecución de Mono (motor de juego de Unity).
fuente
Solo quiero agregar que si necesita hacer estas cosas para las pruebas unitarias, puede usar:
A) La clase PrivateObject
B) Aún necesitará una instancia de PrivateObject, pero puede generar objetos "Accessor" con Visual Studio. Cómo: regenerar accesos privados
Si está configurando campos privados de un objeto en su código fuera de las pruebas unitarias, esa sería una instancia de "olor de código". Creo que quizás la única otra razón por la que querría hacer esto es si está tratando con un tercero biblioteca y no puede cambiar el código de la clase de destino. Incluso entonces, probablemente desee ponerse en contacto con el tercero, explicar su situación y ver si no siguen adelante y cambian su código para satisfacer sus necesidades.
fuente