我的目标是在运行时创建一个委托,它可以将readonly
任何引用类型中的任何字段(包括 )设置为用户指定的值。不幸的是,当包含类型的程序集指定属性时,我当前的实现会VerificationException
在运行时抛出一个。[AllowPartiallyTrustedCallers]
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; }
}
Main
:
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
which 有一个 readonly TypeTwo
。在这种情况下,在运行时DynamicMethod
抛出 a VerificationException
。
是否可以创建这样一个委托,它适用于您抛出的任何声明类型 + 字段类型?如果是这样,怎么做?
我意识到readonly
不应该在构建后设置字段,但这样做的目的是为了反序列化和深度复制。