c# – 创建DynamicMethod以在任何类型上设置只读字段

c# – 创建DynamicMethod以在任何类型上设置只读字段,第1张

概述我的目标是在运行时创建一个委托,可以将任何引用类型中的任何字段(包括readonly)设置为用户指定的值.不幸的是,当包含类型的程序集指定[AllowPartiallyTrustedCallers]属性时,我的当前实现会在运行时抛出VerificationException. AssemblyOne: [assembly: AllowPartiallyTrustedCallers]public 我的目标是在运行时创建一个委托,可以将任何引用类型中的任何字段(包括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)]

另请注意,此代码使用了大量未记录的功能,并且可能随时停止工作.使用风险自负.

总结

以上是内存溢出为你收集整理的c# – 创建DynamicMethod以在任何类型上设置只读字段全部内容,希望文章能够帮你解决c# – 创建DynamicMethod以在任何类型上设置只读字段所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1232785.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-06
下一篇 2022-06-06

发表评论

登录后才能评论

评论列表(0条)

保存