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




field readonly (8)

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

Answers

Vous pouvez:

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

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.


Je suis d'accord avec les autres réponses dans la mesure où cela fonctionne généralement et surtout avec le commentaire de E. Lippert que ce n'est pas un comportement documenté et donc pas de code évolutif.

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

Nous venons de voir un cas où notre code fonctionnait correctement sur nos machines, mais nous avons reçu une VerificationException lorsque le code était exécuté dans un environnement restreint. Le coupable était un appel de réflexion à l'auteur d'un champ en lecture seule. Cela a fonctionné quand nous avons enlevé la restriction en lecture seule de ce champ.


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.


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.)


Une autre façon simple de le faire en utilisant non sécurisé (ou vous pouvez passer le champ à une méthode C via DLLImport et le définir 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);
        }
    }
}

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).


IsAssignableFrom est maintenant déplacé vers TypeInfo alors .... typeof (ISMSRequest) .GetTypeInfo (). IsAssignableFrom (typeof (T) .GetTypeInfo ())





c# reflection field readonly