我正在尝试编写可以在调用者提供的对象上设置任意字段的代码,这些字段可能包含匿名字段。创建委托是不可能的(表达式编译器意识到匿名对象'字段是只读的),所以我选择发出一些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>));
}
}
答案 0 :(得分:0)
您所看到的绝对符合规格。看看ECMA-335 Section II.16.1.2:
<强> initonly 强> 标记在初始化后保持不变的字段。这些字段只能变异 在构造函数中。如果该字段是静态字段,则它应仅在类型初始值设定项内变异 它被宣布的类型。如果它是一个实例字段,那么它只能在其中一个字段中进行变异 定义它的类型的实例构造函数。它不得以任何其他方法或变异进行变异 在任何其他构造函数中,包括派生类的构造函数。
[ 注意: 指某东西的用途 ldflda 要么 ldsflda 在...上 initonly 字段使代码无法验证。 在无法验证的代码中, VES无需检查是否 initonly 字段在构造函数之外变异。 VES需要 如果方法更改常量的值,则不报告任何错误。但是,此类代码无效。 结束 注意 ]
要优雅地处理此案例,您可以使用FieldInfo.IsInitOnly Property。