gpt4 book ai didi

c# - 使用 FieldInfo.SetValue 与 LINQ 表达式在结构中设置字段

转载 作者:太空狗 更新时间:2023-10-30 01:02:50 25 4
gpt4 key购买 nike

我想使用 LINQ 表达式设置私有(private)字段。我有这段代码:

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

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

setter(someObject, someValue);

type变量指定目标的Typefield变量是一个FieldInfo,指定要设置的字段。

这对引用类型非常有用,但是如果目标是一个结构,那么这个东西会将目标作为副本传递给 setter 委托(delegate)并在副本上设置值,而不是像在原始目标上设置值我想。 (至少这是我认为正在发生的事情。)

另一方面,

field.SetValue(someObject, someValue);

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

为了使用编译表达式设置目标字段,我能做些什么吗?

最佳答案

对于值类型,使用 Expression.Unbox而不是 Expression.Convert .

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

这是一个演示:.NET Fiddle


问:setter 方法没有ref 参数。它如何更新原始结构?

答:虽然确实没有 ref 关键字,值类型通常按值传递并因此被复制,这里是 target< 的类型 参数是对象。如果参数是装箱的结构,则对该框的引用将(按值)传递给该方法。

现在,不可能使用纯 C# 来改变装箱结构,因为 C# 拆箱转换总是会生成装箱值的副本。但是 使用 IL 或反射是可能的:

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 表达式使用 Expression.Convert,为什么 setter 不起作用?

A: Expression.Convert 编译为 unbox.any IL 指令,它返回 target 引用的结构的副本。 setter 然后更新这个副本(随后被丢弃)。

问:为什么 Expression.Unbox 解决了这个问题?

A: Expression.Unbox(当用作 Expression.Assign 的目标时)编译为 unbox IL 指令,返回一个指向target 引用的结构的指针。然后 setter 使用指针直接修改该结构。

关于c# - 使用 FieldInfo.SetValue 与 LINQ 表达式在结构中设置字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32158399/

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