生成动态的方法来设置使用反射的结构的一个领域,而不是 [英] Generate dynamic method to set a field of a struct instead of using reflection

查看:206
本文介绍了生成动态的方法来设置使用反射的结构的一个领域,而不是的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

让我们说我有以下的code的更新一个结构使用反射的领域。由于结构实例被复制到 DynamicUpdate 方法,<一个href="http://stackoverflow.com/questions/448158/reflection-on-structure-differs-from-class-but-only-in-$c$c/450453#450453">it需要被传递的之前盒装到对象

Let's say I have the following code which update a field of a struct using reflection. Since the struct instance is copied into the DynamicUpdate method, 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);
    }
}

在code正常工作。现在,让我们说,我不想使用反射,因为它的速度慢。相反,我要产生一些CIL直接修改 ID 字段,将其转换成CIL一个可重用的委托(比方说,使用动态方法的特征)。特别地,我想,以取代上述code与S / T是这样的:

The code works fine. Now, let's say I don't want to use reflection because it's slow. Instead, I want to generate some CIL directly modifying the id field and convert that CIL into a reusable delegate (say, using Dynamic Method feature). Specially, I want to replace the above code with s/t like this:

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 节选

My question: is there any way to implement CreateSetIdDelegate excepts from using one of the following techniques?

  1. 生成CIL的调用使用反射(如在这篇文章的第1 code段)的制定者。这是没有意义的,因为需求是摆脱反思,但它是一个可能实现,所以我只是提了。
  2. 而不是使用动作&LT的,对象,对象&gt; ,使用其签名是一个自定义委托公共委托无效二传手(Ref对象的目标,对象值)
  3. 而不是使用动作&LT;对象,对象&gt; ,使用动作&LT;对象[],对象&gt; 的该阵列是所述目标对象的第一元件。
  1. Generate CIL that invoke the setter using reflection (as the 1st code segment in this post). This makes no sense, given the requirement is to get rid of reflection, but it's a possible implementation so I just mention.
  2. Instead of using Action<object, object>, use a custom delegate whose signature is public delegate void Setter(ref object target, object value).
  3. Instead of using Action<object, object>, use Action<object[], object> with the 1st element of the array being the target object.

我之所以不喜欢2及3是因为我不希望有不同的委托对象和结构的setter方法​​(setter方法​​,以及不想让集对象场代表不是必须的,如更复杂的动作&LT;对象,对象&gt; )。我估计 CreateSetIdDelegate 的实施将产生不同的CIL根据目标类型是结构或对象,但我希望它返回相同的委托,提供相同的API用户。

The reason I don't like 2 & 3 is because I don't want to have different delegates for the setter of object and setter of struct (as well as not wanting to make the set-object-field delegate more complicated than necessary, e.g. Action<object, object>). I reckon that the implementation of CreateSetIdDelegate would generate different CIL depending whether the target type is struct or object, but I want it to return the same delegate offering the same API to user.

推荐答案

修改再次:该作品结构现在

有一个华丽的方式做到这一点在C#4,但你必须写自己的的ILGenerator 发出$ C $下之前的事情。他们增加了一个防爆pressionType.Assign 到.NET Framework 4。

There's a gorgeous way to do it in C# 4, but you'll have to write your own ILGenerator emit code for anything before that. They added an ExpressionType.Assign to the .NET Framework 4.

这工作在C#4(测试):

This works in C# 4 (tested):

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

编辑:这是我的测试code

Here was my test code.

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

这篇关于生成动态的方法来设置使用反射的结构的一个领域,而不是的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆