gpt4 book ai didi

c# - 在 C# 中使用表达式访问结构属性

转载 作者:太空宇宙 更新时间:2023-11-03 13:15:12 25 4
gpt4 key购买 nike

我一直在使用以下代码来缓存属性 getter/setter 委托(delegate),以便快速访问该功能:

class PropertyHelper
{
public static Func<object, object> BuildGetter(PropertyInfo propertyInfo)
{
var method = propertyInfo.GetGetMethod(true);

var obj = Expression.Parameter(typeof(object), "o");
Expression<Func<object, object>> expr =
Expression.Lambda<Func<object, object>>(
Expression.Convert(
Expression.Call(
Expression.Convert(obj, method.DeclaringType),
method),
typeof(object)),
obj);
return expr.Compile();
}

public static Action<object, object> BuildSetter(PropertyInfo propertyInfo)
{
var method = propertyInfo.GetSetMethod(true);

var obj = Expression.Parameter(typeof(object), "o");
var value = Expression.Parameter(typeof(object));

Expression<Action<object, object>> expr =
Expression.Lambda<Action<object, object>>(
Expression.Call(
Expression.Convert(obj, method.DeclaringType),
method,
Expression.Convert(value, method.GetParameters()[0].ParameterType)),
obj,
value);

Action<object, object> action = expr.Compile();
return action;
}
}

这在访问类对象的属性时效果很好,但当我将它用于结构对象时却失败了。例如,考虑以下代码:

public struct LocationStruct
{
public double X { get; set; }
public double Y { get; set; }
}

public class LocationClass
{
public double X { get; set; }
public double Y { get; set; }
}

public class Tester
{
public static void TestSetX()
{
Type locationClassType = typeof(LocationClass);
PropertyInfo xProperty = locationClassType.GetProperty("X");
Action<object, object> setter = PropertyHelper.BuildSetter(xProperty);

LocationStruct testLocationClass = new LocationClass();
setter(testLocationClass, 10.0);
if (testLocationClass.X == 10.0)
{
MessageBox.Show("Worked for the class!");
}


Type locationStructType = typeof(LocationStruct);
xProperty = locationStructType.GetProperty("X");
setter = PropertyHelper.BuildSetter(xProperty);

LocationStruct testLocationStruct = new LocationStruct();
setter(testLocationStruct, 10.0);
if (testLocationStruct.X != 10.0)
{
MessageBox.Show("Didn't work for the struct!");
}
}
}

第一部分有效,将 testLocationClass 的 X 值设置为 10。但是,因为 LocationStruct 是一个结构,所以 testLocationStruct 是按值传入的,该值(在委托(delegate)调用的方法内部)将其 X 设置为10,但上面代码块中的testLocationStruct对象保持不变。

因此,我需要一种方法来访问类似于上述方法的结构对象的属性(仅适用于类对象的属性)。我尝试使用“按引用传递”模式来完成此操作,但我就是无法让它工作。

谁能提供类似的 BuildGetter 和 BuildSetter 方法来缓存结构属性值的 getter/setter 委托(delegate)?

最佳答案

您需要注意两件事才能使其正常工作:

  1. 创建setter表达式树时,需要对值类型使用Expression.Unbox,对引用类型使用Expression.Convert
  2. 使用值类型调用 setter 时,您需要确保它被装箱以使用指向结构的指针设置值(而不是处理结构的副本)。

新的实现看起来像这样(只显示新的 setter 和测试方法,因为其余的都是一样的):

public static Action<object, object> BuildSetter(PropertyInfo propertyInfo)
{
// Note that we are testing whether this is a value type
bool isValueType = propertyInfo.DeclaringType.IsValueType;
var method = propertyInfo.GetSetMethod(true);
var obj = Expression.Parameter(typeof (object), "o");
var value = Expression.Parameter(typeof (object));

// Note that we are using Expression.Unbox for value types
// and Expression.Convert for reference types
Expression<Action<object, object>> expr =
Expression.Lambda<Action<object, object>>(
Expression.Call(
isValueType ?
Expression.Unbox(obj, method.DeclaringType) :
Expression.Convert(obj, method.DeclaringType),
method,
Expression.Convert(value, method.GetParameters()[0].ParameterType)),
obj, value);
Action<object, object> action = expr.Compile();
return action;
}

调用编译后的setter的代码:

...
Type locationStructType = typeof (LocationStruct);
xProperty = locationStructType.GetProperty("X");
setter = PropertyHelper.BuildSetter(xProperty);
LocationStruct testLocationStruct = new LocationStruct();

// Note the boxing of the struct before calling the setter
object boxedStruct = testLocationStruct;
setter(boxedStruct, 10.0);
testLocationStruct = (LocationStruct)boxedStruct;
...

这打印:

Worked for the class!
Worked for the struct!

我还准备了一个 .Net fiddle,它显示了这里的工作实现:https://dotnetfiddle.net/E6WZmK

有关 Expression.Unbox 步骤的说明,请参阅此答案:https://stackoverflow.com/a/32158735/521773

关于c# - 在 C# 中使用表达式访问结构属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26643430/

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