Can I change a private readonly field in C# using reflection?
我想知道,由于很多事情都可以通过反射来完成,在构造函数完成执行之后,我可以更改一个私有的只读字段吗?(注:只是好奇)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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 |
你可以:
1 2 3 |
显而易见的是尝试一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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有不同的规则,有趣的是,您必须显式地设置EDCOX1 0),以便于访问,并且它只适用于实例字段。)
我同意其他的答案,因为它通常是有效的,特别是E.Lippert的评论,这不是文档化的行为,因此不是未来的证明代码。
然而,我们也注意到了另一个问题。如果您在具有受限权限的环境中运行代码,则可能会出现异常。
我们刚刚遇到一个案例,我们的代码在我们的机器上运行得很好,但是当代码在受限环境中运行时,我们收到了一个
你问为什么要像那样破坏封装。
我使用实体助手类来水合物实体。这将使用反射获取新空实体的所有属性,并将属性/字段名与结果集中的列匹配,并使用propertyinfo.setvalue()设置它。
我不希望其他任何人能够改变这个值,但我也不想全力以赴为每个实体定制代码水合方法。
我的许多存储过程返回的结果集与表或视图不直接对应,因此代码生成ORM对我没有任何作用。
另一种简单的方法是使用不安全的(或者您可以通过dllimport将字段传递给C方法并将其设置在那里)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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); } } } |
不要这样做。
我刚刚花了一天时间修复了一个超现实的bug,对象不能是它们自己声明的类型。
修改只读字段工作一次。但是如果你再次尝试修改它,你会得到这样的情况:
1 2 3 | SoundDef mySound = Reflection_Modified_Readonly_SoundDef_Field; if( !(mySound is SoundDef) ) Log("Welcome to impossible-land!"); //This would run |
所以不要这样做。
这是在Mono运行时(Unity游戏引擎)。
答案是肯定的,但更重要的是:
你为什么要这么做?故意破坏封装对我来说似乎是一个非常糟糕的主意。
使用反射来改变一个只读或常量字段,就像是将意想不到的结果定律与墨菲定律结合在一起。
我只是想补充一下,如果您需要为单元测试做这些事情,那么您可以使用:
a)privateObject类
b)您仍然需要privateObject实例,但可以使用Visual Studio生成"accessor"对象。如何:重新生成专用访问器
如果您在单元测试之外设置代码中某个对象的私有字段,那么这就是"代码气味"的一个实例,我认为您可能希望这样做的唯一其他原因是,如果您正在处理第三方库,并且不能更改目标类代码。即便如此,您可能还是希望联系第三方,解释您的情况,看看他们是否会继续进行,并更改他们的代码以满足您的需要。