代码之家  ›  专栏  ›  技术社区  ›  Ron Klein Noa Kuperberg

我可以使用反射更改C#中的私有只读字段吗?

  •  128
  • Ron Klein Noa Kuperberg  · 技术社区  · 17 年前

    我想知道,由于很多事情都可以使用反射来完成,我可以在构造函数完成执行后更改私有只读字段吗?
    (注:只是好奇)

    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
    
    9 回复  |  直到 16 年前
        1
  •  141
  •   Philippe Leybaert    17 年前

    你可以:

    typeof(Foo)
       .GetField("bar",BindingFlags.Instance|BindingFlags.NonPublic)
       .SetValue(foo,567);
    
        2
  •  52
  •   Jon Skeet    17 年前

    显而易见的是尝试一下:

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

    这很好用。(有趣的是,Java有不同的规则——你必须显式地设置 Field

        3
  •  12
  •   Andreas    13 年前

    尤其是E.Lippert的评论,即这不是有记录的行为,因此也不是面向未来的代码。

    我们刚刚遇到一个案例,我们的代码在我们的机器上运行良好,但我们收到了 VerificationException

        4
  •  4
  •   Necroposter    16 年前

    你问为什么要这样破坏封装。

    我使用实体辅助类来水合实体。这使用反射来获取新空实体的所有属性,并将属性/字段名与结果集中的列相匹配,然后使用propertyinfo.setvalue()来设置它。

    我的许多存储过程返回的结果集并不直接对应于表或视图,因此代码生成ORM对我没有任何帮助。

        5
  •  2
  •   Powerlord    17 年前

    别这样。

    我刚刚花了一天时间修复了一个超现实的bug,在这个bug中,对象可能不是自己声明的类型。

    修改只读字段只工作了一次。但如果你试图再次修改它,你会得到这样的情况:

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

    所以不要这样做。

        6
  •  2
  •   Tynan Sylvester    12 年前

    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);
            }
        }
    }
    
        7
  •  2
  •   zezba9000    8 年前

    你为什么要这么做?在我看来,故意破坏封装似乎是一个极其糟糕的主意。

    Law of Unintended Consequences Murphy's Law .

        8
  •  0
  •   Dudeman3000    13 年前

    A) The PrivateObject

    How to: Regenerate Private Accessors

    如果你在单元测试之外的代码中设置对象的私有字段,这将是“代码气味”的一个例子。我认为,你想这样做的唯一其他原因可能是,如果你正在处理第三方库,并且无法更改目标类代码。即便如此,你可能还是想联系第三方,解释你的情况,看看他们是否不会继续修改代码以满足你的需求。