gpt4 book ai didi

c# - 生成动态方法来设置结构的字段而不是使用反射

转载 作者:可可西里 更新时间:2023-11-01 08:32:23 26 4
gpt4 key购买 nike

假设我有以下代码更新 struct 的字段使用反射。由于结构实例被复制到 DynamicUpdate方法,it needs to be boxed to an object before being passed .

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);
}
}

代码运行良好。现在,假设我不想使用反射,因为它很慢。相反,我想生成一些 CIL 直接修改 id字段并将该 CIL 转换为可重用委托(delegate)(例如,使用动态方法功能)。特别地,我想用这样的 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除了使用以下技术之一?

  1. 生成使用反射调用 setter 的 CIL(作为本文中的第一个代码段)。这是没有意义的,因为要求是摆脱反射,但这是一个可能的实现,所以我只是提到。
  2. 而不是使用 Action<object, object> , 使用签名为 public delegate void Setter(ref object target, object value) 的自定义委托(delegate).
  3. 而不是使用 Action<object, object> , 使用 Action<object[], object>数组的第一个元素是目标对象。

我不喜欢 2 和 3 的原因是因为我不想为对象的 setter 和 struct 的 setter 使用不同的委托(delegate)(也不想让 set-object-field 委托(delegate)更复杂不必要的,例如 Action<object, object> )。我估计 CreateSetIdDelegate 的执行会根据目标类型是结构还是对象生成不同的 CIL,但我希望它返回向用户提供相同 API 的相同委托(delegate)。

最佳答案

再次编辑:现在结构有效。

在 C# 4 中有一种绝妙的方法可以做到这一点,但在此之前您必须编写自己的 ILGenerator 发出代码。他们向 .NET Framework 4 添加了 ExpressionType.Assign

这适用于 C# 4(已测试):

public delegate void ByRefStructAction(ref SomeType instance, object value);

private static ByRefStructAction BuildSetter(FieldInfo field)
{
ParameterExpression instance = Expression.Parameter(typeof(SomeType).MakeByRefType(), "instance");
ParameterExpression value = Expression.Parameter(typeof(object), "value");

Expression<ByRefStructAction> expr =
Expression.Lambda<ByRefStructAction>(
Expression.Assign(
Expression.Field(instance, field),
Expression.Convert(value, field.FieldType)),
instance,
value);

return expr.Compile();
}

编辑:这是我的测试代码。

public struct SomeType
{
public int member;
}

[TestMethod]
public void TestIL()
{
FieldInfo field = typeof(SomeType).GetField("member");
var setter = BuildSetter(field);
SomeType instance = new SomeType();
int value = 12;
setter(ref instance, value);
Assert.AreEqual(value, instance.member);
}

关于c# - 生成动态方法来设置结构的字段而不是使用反射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1272454/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com