128 votes

Puis-je modifier un champ privé en lecture seule en C# en utilisant la réflexion ?

Je me demande, puisque beaucoup de choses peuvent être faites en utilisant la réflexion, si je peux modifier un champ privé en lecture seule après que le constructeur ait terminé son exécution.
(note : simple 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

167voto

Philippe Leybaert Points 62715

Vous pouvez :

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

56voto

Jon Skeet Points 692016

La chose la plus évidente est d'essayer :

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

Cela fonctionne bien. (Il est intéressant de noter que Java a des règles différentes - vous devez explicitement définir le paramètre Field pour être accessible, et cela ne fonctionnera de toute façon que pour les champs d'instance).

11voto

Andreas Points 3896

Je suis d'accord avec les autres réponses pour dire que cela fonctionne en général et surtout avec le commentaire d'E. Lippert selon lequel il ne s'agit pas d'un comportement documenté et donc d'un code qui n'est pas à l'épreuve du temps.

Cependant, nous avons également remarqué un autre problème. Si vous exécutez votre code dans un environnement où les autorisations sont restreintes, vous risquez d'obtenir une exception.

Nous venons d'avoir un cas où notre code fonctionnait correctement sur nos machines, mais nous avons reçu un VerificationException lorsque le code est exécuté dans un environnement restreint. Le coupable était un appel par réflexion au setter d'un champ en lecture seule. Cela a fonctionné lorsque nous avons supprimé la restriction de lecture seule de ce champ.

5voto

Necroposter Points 21

Vous avez demandé pourquoi vous vouliez rompre l'encapsulation de cette manière.

J'utilise une classe d'aide pour hydrater les entités. Elle utilise la réflexion pour obtenir toutes les propriétés d'une nouvelle entité vide, et fait correspondre le nom de la propriété/du champ à la colonne dans le jeu de résultats, et le définit en utilisant propertyinfo.setvalue().

Je ne veux pas que quelqu'un d'autre puisse modifier la valeur, mais je ne veux pas non plus faire l'effort de coder des méthodes d'hydratation personnalisées pour chaque entité.

La plupart de mes procs stockées renvoient des résultats qui ne correspondent pas directement à des tables ou à des vues, de sorte que le code gen ORM ne m'est d'aucune utilité.

2voto

Powerlord Points 43989

La réponse est oui, mais plus important encore :

Pourquoi voudriez-vous le faire ? Rompre intentionnellement l'encapsulation me semble être une très mauvaise idée.

L'utilisation de la réflexion pour modifier un champ en lecture seule ou un champ constant revient à combiner la fonction La loi des conséquences involontaires avec La loi de Murphy .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X