我正在尝试编写代码,可以在调用者提供的对象上设置任意字段,其中可能包括匿名对象。创建委托是不可能的(表达式编译器意识到匿名对象的字段是只读的),所以我选择发出一些IL。然而,在这样做的时候,我遇到了VerificationException (“操作可能会破坏运行时的稳定性”)。同样简单的代码在具有常规字段的对象上运行得很好。只读字段失败。这里还能做些什么呢?我运行的是.Net 4.6.2。
提前感谢!
class TestRegular
{
private string field;
}
class TestReadOnly
{
private readonly string field;
}
class Program
{
static void Main(string[] args)
{
Verify(new TestRegular()); // this works
Verify(new TestReadOnly()); // this does not work
Verify(new { field = "abc" }); // this does not work
Console.WriteLine("Done");
}
private static void Verify<T>(T test)
{
var fields = typeof(T).GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
Action <T, object> setter = CompileSetter<T>(fields[0]);
setter(test, "value");
}
private static Action<TResult, object> CompileSetter<TResult>(FieldInfo field)
{
string methodName = field.ReflectedType.FullName + ".TestSetter";
DynamicMethod setterMethod = new DynamicMethod(methodName, null, new[] { typeof(TResult), typeof(object) }, true);
ILGenerator gen = setterMethod.GetILGenerator();
gen.Emit(OpCodes.Ldarg_0);
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Castclass, field.FieldType);
gen.Emit(OpCodes.Stfld, field);
gen.Emit(OpCodes.Ret);
return (Action<TResult, object>)setterMethod.CreateDelegate(typeof(Action<TResult, object>));
}
}发布于 2017-12-03 22:50:34
你所看到的绝对符合规格。看一看ECMA-335 Section II.16.1.2
initonly标记初始化后保持不变的字段。这些字段只能在构造函数中发生变化。如果字段是静态字段,则只应在声明它的类型的类型初始值设定项中对其进行变异。如果它是一个实例字段,那么它只能在定义它的类型的一个实例构造函数中发生变化。它不应在任何其他方法或任何其他构造函数中发生变化,包括派生类的构造函数。
注意:在initonly字段上使用ldflda或ldsflda会使代码无法验证。在不可验证的代码中,VES不需要检查initonly字段是否在构造函数外部发生了变化。如果方法更改了常量的值,则VES不需要报告任何错误。但是,这样代码不是有效的。结束音符
要优雅地处理这种情况,可以使用FieldInfo.IsInitOnly Property。
https://stackoverflow.com/questions/47603978
复制相似问题