假设我有以下代码更新struct
使用反射的字段。由于结构实例被复制到DynamicUpdate
方法中,因此在传递之前需要将其装箱到对象中。
struct Person
{
public int id;
}
class Test
{
static void Main()
{
object person = RuntimeHelpers.GetObjectValue(new Person());
DynamicUpdate(person);
Console.WriteLine(((Person)person).id); // print 10
}
private static void DynamicUpdate(object o)
{
FieldInfo field = typeof(Person).GetField("id");
field.SetValue(o, 10);
}
}
代码工作正常。现在,假设我不想使用反射,因为它很慢。相反,我想生成一些直接修改id
字段的 CIL 并将该 CIL 转换为可重用的委托(例如,使用动态方法功能)。特别是,我想用 s/t 替换上面的代码,如下所示:
static void Main()
{
var action = CreateSetIdDelegate(typeof(Person));
object person = RuntimeHelpers.GetObjectValue(new Person());
action(person, 10);
Console.WriteLine(((Person)person).id); // print 10
}
private static Action<object, object> CreateSetIdDelegate(Type t)
{
// build dynamic method and return delegate
}
我的问题:有没有办法CreateSetIdDelegate
通过使用以下技术之一来实现例外?
- 生成使用反射调用设置器的 CIL(作为本文中的第一个代码段)。这是没有意义的,因为要求是摆脱反射,但这是一种可能的实现,所以我只提一下。
- 不要使用
Action<object, object>
,而是使用签名为 的自定义委托public delegate void Setter(ref object target, object value)
。 - 而不是使用
Action<object, object>
,使用Action<object[], object>
数组的第一个元素作为目标对象。
我不喜欢 2 和 3 的原因是因为我不想为 object 的 setter 和 struct 的 setter 使用不同的委托(也不想让 set-object-field 委托比必要的更复杂,例如Action<object, object>
)。我认为CreateSetIdDelegate
根据目标类型是结构还是对象,实现会生成不同的 CIL,但我希望它返回向用户提供相同 API 的相同委托。