c# – 创建DynamicMethod以在任何类型上设置只读字段
我的目标是在运行时创建一个委托,可以将任何引用类型中的任何字段(包括readonly)设置为用户指定的值.不幸的是,当包含类型的程序集指定[AllowPartiallyTrustedCallers]属性时,我的当前实现会在运行时抛出VerificationException.
AssemblyOne: [assembly: AllowPartiallyTrustedCallers] public class TypeOne { public TypeOne(TypeTwo typeTwoField) { this.TypeTwoField = typeTwoField; } public TypeTwo TypeTwoField { get; } } AssemblyTwo: [assembly: AllowPartiallyTrustedCallers] public class TypeTwo { public TypeTwo(int i) { this.Int = i; } public int Int { get; } } 主要: using System; using System.Reflection; using System.Reflection.Emit; using AssemblyOne; using AssemblyTwo; namespace Main { class Program { public class MyType { public MyType(TypeOne typeOneField) { this.TypeOneField = typeOneField; } public TypeOne TypeOneField { get; } } static void Main(string[] args) { var fieldInfo = typeof(TypeOne) .GetTypeInfo() .GetField( "<TypeTwoField>k__BackingField",BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); var setter = (Action<TypeOne,TypeTwo>) GetReferenceSetter(fieldInfo); var myType = new MyType(new TypeOne(new TypeTwo(1))); // Throws VerificationException setter(myType.TypeOneField,new TypeTwo(2)); } public static Delegate GetReferenceSetter(FieldInfo field) { var delegateType = typeof(Action<,>) .MakeGenericType(field.DeclaringType,field.FieldType); var method = new DynamicMethod( field.Name + "Set",null,new[] {field.DeclaringType,field.FieldType},field.DeclaringType,skipVisibility: true); var emitter = method.GetILGenerator(); emitter.Emit(OpCodes.Ldarg_0); emitter.Emit(OpCodes.Ldarg_1); emitter.Emit(OpCodes.Stfld,field); emitter.Emit(OpCodes.Ret); return method.CreateDelegate(delegateType); } } } 所以MyType有一个TypeOne,它有一个只读的TypeTwo.在这种情况下,DynamicMethod在运行时抛出VerificationException. 是否有可能创建一个适用于您抛出的任何声明类型字段类型的委托?如果是这样,怎么样? 我意识到在构造之后永远不会设置只读字段,但是这样做的目的是用于反序列化&深拷贝. 解决方法
动态方法在修改其安全性方面非常有限.我怀疑使用AssemblyBuilder可能会绕过安全检查,但我没有尝试过.
相反,可以实现此目的的是使用其他方法来访问TypedReference类型中的字段. public static unsafe void SetValue<T>(object inst,FieldInfo fi,T val) { var mi = typeof(TypedReference).GetMethod("InternalMakeTypedReference",BindingFlags.NonPublic | BindingFlags.Static); var sig = MethodSignature.FromMethodInfo(mi); var del = ReflectionTools.NewCustomDelegateType(sig.ReturnType,sig.ParameterTypes); var inv = mi.CreateDelegate(del); TypedReference tr; var ptr = Pointer.Box(&tr,typeof(void*)); inv.DynamicInvoke(ptr,inst,new[]{fi.FieldHandle.Value},fi.FieldType); __refvalue(tr,T) = val; } FromMethodInfo和NewCustomDelegateType来自SharpUtils,需要调用InternalMakeTypedReference,它能够获得对任何字段的引用.它的签名如下: private unsafe static extern void InternalMakeTypedReference(void* result,object target,IntPtr[] flds,RuntimeType lastFieldType); 您可以用自己的库替换库方法,只需要构建适当的委托类型(由于指针而无法使用Action).由于内部RuntimeType,您无法直接创建委托类型.令人惊讶的是,DynamicInvoke在委托上工作,并创建了类型引用. 但是,要使用这个伏都教,我不得不降低组件中的安全检查,所以我不确定它是否也适用于你的装配系统: [assembly: System.Security.SecurityRules(System.Security.SecurityRuleSet.Level1,SkipVerificationInFullTrust=true)] 另请注意,此代码使用了大量未记录的功能,并且可能随时停止工作.使用风险自负. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |