【发布时间】:2020-08-14 20:33:12
【问题描述】:
我们知道静态构造函数是在第一次调用类时调用的。
我们现在有一个类:
static class Demo
{
private readonly static int _intValue;
static Demo ()
{
_intValue = 5;
}
}
在访问Demo 时将调用构造函数。值 5 将分配给 _intValue 只读字段。之后,我们可以再次通过反射设置值:
typeof (Demo)
.GetField ("_ intValue", BindingFlags.Static | BindingFlags.NonPublic)
.SetValue (null, 567);
为什么值5 可以被覆盖?它不是已经在构造函数中初始化了吗?为什么不抛出System.FieldAccessException?
在 NET Core 3.1 中测试。完整示例https://dotnetfiddle.net/4DsJ6H
更新: 我找到了一种方法来覆盖只读静态字段,即使它被请求一次。它基于通过 IL 生成的方法。实际上,除了最初的问题 - 这种解决方法是如何工作的?
【问题讨论】:
-
Reflection 让您可以做普通 C# 代码甚至编译后的 IL 代码通常做不到的事情。例如,您可以从其声明类型之外调用私有方法。这似乎是一个类似的案例。
-
@JoeSewell 为什么你没有提到它作为答案?
-
@JoeSewell 我很感兴趣这个任务是如何详细完成的,它绕过了只读字段的限制?这是由环境提供的吗?为什么?或者这只是 .NET Core 的一个特性?例如,在 NET Framework 4.7 中,通过反射根本找不到静态只读字段。这有什么关系吗?我只是不知道要掌握什么才能更好地理解问题中描述的行为。
-
“在 NET Framework 4.7 中,根本不会通过反射找到静态只读字段”——这根本不是真的;而在 .net core 3.1 中,您 不能 依赖于能够通过反射获得静态 ReadOnly 字段,因为它会影响某些新的 JIT 优化(但这可能仅适用于 ref 类型(类),对于去虚拟化)
-
这里是@MarcGravell 的更深层次的discussion。
标签: c# reflection