使用FieldInfo.SetValue VS LINQ EX pressions在一个结构设置字段 [英] Using FieldInfo.SetValue vs LINQ expressions to set a field in a struct

查看:138
本文介绍了使用FieldInfo.SetValue VS LINQ EX pressions在一个结构设置字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要设置使用LINQ EX pressions私人领域。我有这个code:

I want to set private fields using LINQ expressions. I have this code:

//parameter "target", the object on which to set the field `field`
ParameterExpression targetExp = Expression.Parameter(typeof(object), "target");

//parameter "value" the value to be set in the `field` on "target"
ParameterExpression valueExp = Expression.Parameter(typeof(object), "value");

//cast the target from object to its correct type
Expression castTartgetExp = Expression.Convert(targetExp, type);

//cast the value to its correct type
Expression castValueExp = Expression.Convert(valueExp, field.FieldType);

//the field `field` on "target"
MemberExpression fieldExp = Expression.Field(castTartgetExp, field);

//assign the "value" to the `field` 
BinaryExpression assignExp = Expression.Assign(fieldExp, castValueExp);

//compile the whole thing
var setter = Expression.Lambda<Action<object, object>> (assignExp, targetExp, valueExp).Compile();

这编译一个委托,它接受两个对象,目标和值:

This compiles a delegate that takes two objects, the target and the value:

setter(someObject, someValue);

键入变量指定键入目标,而字段<的/ code>变量是一个字段信息指定要设置的字段。

The type variable specifies the Type of the target, and the field variable is a FieldInfo that specifies the field to be set.

这对于引用类型的伟大工程,但如果目标是一个结构,那么这个东西会通过在目标作为副本给setter的委托,并设置值的副本,而不是设置像原始目标的价值我要。 (至少这是我觉得是怎么回事。)

This works great for reference types, but if the target is a struct, then this thing will pass the target as a copy to the setter delegate and set the value on the copy, instead of setting the value on the original target like I want. (At least that is what I think is going on.)

在另一方面,

field.SetValue(someObject, someValue);

工作得很好,即使是结构。

works just fine, even for structs.

有什么我可以做这是为了使用编译前pression设定目标的领域?

Is there anything I can do about this in order to set the field of the target using the compiled expression?

推荐答案

对于值类型,使用<一个href="https://msdn.microsoft.com/en-us/library/system.linq.ex$p$pssions.ex$p$pssion.unbox(v=vs.110).aspx"相对=nofollow>防爆pression.Unbox的代替的防爆pression.Convert

For value types, use Expression.Unbox instead of Expression.Convert.

//cast the target from object to its correct type
Expression castTartgetExp = type.IsValueType
    ? Expression.Unbox(targetExp, type)
    : Expression.Convert(targetExp, type);

下面是一个演示: .NET小提琴

问:二传手方法没有一个 REF 参数。它如何更新原有的结构?

Q: The setter method doesn't have a ref parameter. How can it update the original struct?

答:虽然这是真的,如果没有 REF 关键字,值类型通常按值传递的,因此复制,这里的类型在目标参数对象。如果参数是一个盒装的结构,那么引用应用于箱传递(按价值计算)的方法。

A: Although it's true that, without the ref keyword, value types are normally passed by value and thus copied, here the type of the target parameter is object. If the argument is a boxed struct, then a reference to the box is passed (by value) to the method.

现在,它采用纯C#变异装箱的结构,因为C#装箱转换总是产生装箱值的副本,是不可能的。但它的的可能使用IL或反思:

Now, it's not possible using pure C# to mutate a boxed struct because a C# unboxing conversion always produces a copy of the boxed value. But it is possible using IL or Reflection:

public struct S { public int I; }

public void M(object o, int i)
{
    // ((S)o).I = i; // DOESN'T COMPILE
    typeof(S).GetField("I").SetValue(o, i);
}

public void N()
{
    S s = new S();
    object o = s; // create a boxed copy of s

    M(o, 1); // mutate o (but not s)
    Console.WriteLine(((S)o).I); // "1"
    Console.WriteLine(s.I);      // "0"

    M(s, 2); // mutate a TEMPORARY boxed copy of s (BEWARE!)
    Console.WriteLine(s.I);      // "0"
}

问:为什么不二传手工作,如果在LINQ EX pression使用防爆pression.Convert

答:防爆pression.Convert编译的<一个href="https://msdn.microsoft.com/en-us/library/system.reflection.emit.op$c$cs.unbox_any(v=vs.110).aspx"相对=nofollow> unbox.any IL指令,它返回的复制的被引用的结构的目标。二传手然后更新这个副本(其随后被丢弃)。

A: Expression.Convert compiles to the unbox.any IL instruction, which returns a copy of the struct referenced by target. The setter then updates this copy (which is subsequently discarded).

问:为什么前pression.Unbox解决问题

答:防爆pression.Unbox(为Ex pression.Assign的目标使用时)编译到的 拆箱 IL指令,它返回的指针的由目标引用的结构。设定器然后使用指针直接修改该结构

A: Expression.Unbox (when used as the target of Expression.Assign) compiles to the unbox IL instruction, which returns a pointer to the struct referenced by target. The setter then uses the pointer to modify that struct directly.

这篇关于使用FieldInfo.SetValue VS LINQ EX pressions在一个结构设置字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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