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


Answers

La chose évidente est de l'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. (Java a des règles différentes, intéressant - vous devez explicitement définir le Field pour être accessible, et cela ne fonctionnera que pour les champs d'instance de toute façon.)

Question

Je me demande, puisque beaucoup de choses peuvent être faites en utilisant la réflexion, puis-je changer un champ readonly privé après que le constructeur a terminé son exécution?
(note: juste 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



Vous avez demandé pourquoi vous voudriez casser l'encapsulation comme ça.

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

Je ne veux pas que quelqu'un d'autre puisse changer la valeur, mais je ne veux pas non plus faire tous les efforts pour personnaliser les méthodes d'hydratation pour chaque entité.

Mes nombreux process stockés renvoient des jeux de résultats qui ne correspondent pas directement aux tables ou aux vues, donc les ORM de code gen ne font rien pour moi.




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.

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:

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

Alors ne le fais pas.

C'était sur le runtime Mono (moteur de jeu Unity).




Je veux juste ajouter que si vous avez besoin de 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. Comment: 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 odeur" Je pense que peut-être la seule autre raison pour laquelle vous voulez faire cela est si vous avez affaire à un tiers bibliothèque et vous ne pouvez pas modifier le code de la classe cible. Même alors, vous voulez probablement contacter la 3ème partie, expliquer votre situation et voir s'ils ne vont pas aller de l'avant et modifier leur code pour répondre à vos besoins.