使用FieldInfo.SetValue VS LINQ EX pressions在一个结构设置字段 [英] Using FieldInfo.SetValue vs LINQ expressions to set a field in a struct
问题描述
我要设置使用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屋!