Je me demande, étant donné que beaucoup de choses peuvent être faites en utilisant la réflexion, puis-je changer un champ privé en lecture seule après que le constructeur ait terminé son exécution?
(note: juste de la curiosité)
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
la source
la source
La chose évidente est de l'essayer:
Cela fonctionne très bien. (Java a des règles différentes, ce qui est intéressant - vous devez définir explicitement le
Field
pour qu'il soit accessible, et cela ne fonctionnera que pour les champs d'instance de toute façon.)la source
Je suis d'accord avec les autres réponses dans la mesure où cela fonctionne en général et en particulier avec le commentaire de E. Lippert selon lequel ce n'est pas un comportement documenté et donc pas un code à l'épreuve du temps.
Cependant, nous avons également remarqué un autre problème. Si vous exécutez votre code dans un environnement avec des autorisations restreintes, vous pouvez obtenir une exception.
Nous venons d'avoir un cas où notre code fonctionnait correctement sur nos machines, mais nous avons reçu un message
VerificationException
lorsque le code fonctionnait dans un environnement restreint. Le coupable était un appel de réflexion au poseur d'un champ en lecture seule. Cela a fonctionné lorsque nous avons supprimé la restriction en lecture seule de ce champ.la source
Vous avez demandé pourquoi vous voudriez rompre l'encapsulation comme ça.
J'utilise une classe d'assistance d'entité pour hydrater les entités. Cela utilise la réflexion pour obtenir toutes les propriétés d'une nouvelle entité vide, fait correspondre le nom de la propriété / du champ à la colonne dans le jeu de résultats, et le définit à l'aide de propertyinfo.setvalue ().
Je ne veux pas que quelqu'un d'autre puisse changer la valeur, mais je ne veux pas non plus consacrer tous les efforts nécessaires pour personnaliser les méthodes d'hydratation du code pour chaque entité.
Mes nombreux processus stockés renvoient des ensembles de résultats qui ne correspondent pas directement aux tables ou aux vues, donc les ORM de génération de code ne font rien pour moi.
la source
Un autre moyen simple de le faire en utilisant unsafe (ou vous pouvez passer le champ à une méthode C via DLLImport et le définir ici).
la source
La réponse est oui, mais plus important encore:
Pourquoi voudriez-vous? Briser intentionnellement l'encapsulation me semble une idée horriblement mauvaise.
Utiliser la réflexion pour changer un champ en lecture seule ou constant revient à combiner la loi des conséquences imprévues avec la loi de Murphy .
la source
Ne fais pas ça.
Je viens de passer une journée à corriger un bug surréaliste où les objets pourraient ne pas être de leur propre type déclaré.
La modification du champ en lecture seule a fonctionné une fois. Mais si vous essayez de le modifier à nouveau, vous obtiendrez des situations comme celle-ci:
Alors ne le fais pas.
C'était sur le runtime Mono (moteur de jeu Unity).
la source
Je veux juste ajouter que si vous devez faire cela pour les tests unitaires, vous pouvez utiliser:
A) La classe PrivateObject
B) Vous aurez toujours besoin d'une instance PrivateObject, mais vous pouvez générer des objets "Accessor" avec Visual Studio. Guide pratique: régénérer les accesseurs privés
Si vous définissez des champs privés d'un objet dans votre code en dehors des tests unitaires, ce serait une instance de "code sentir" Je pense que la seule autre raison pour laquelle vous voudriez faire cela est peut-être si vous traitez avec un tiers bibliothèque et vous ne pouvez pas modifier le code de la classe cible. Même dans ce cas, vous voudrez probablement contacter le tiers, expliquer votre situation et voir s'il ne va pas de l'avant et changer son code pour répondre à vos besoins.
la source