Expression.Assign returns 函数而不是动作
Expression.Assign returns Func instead of Action
我正在构建一个基于 属性 分配器的小型表达式。
这个想法很简单,只需创建一个获取一个对象 属性 并将其分配给另一个对象的 Action 属性。
所以如果我处理这个表达式:
public static Action PropertyAssign(object sourceObject, object destObject,
PropertyInfo sourceProperty, PropertyInfo destProperty)
{
Expression source = Expression.PropertyOrField(
Expression.Constant(sourceObject), sourceProperty.Name);
Expression dest = Expression.PropertyOrField(
Expression.Constant(destObject), destProperty.Name);
Expression assign = Expression.Assign(dest, source);
return (Action)Expression.Lambda(assign).Compile();
}
并尝试调用它,我得到一个异常告诉 Expression.Lambda 是 Func 类型(其中 T 是 属性 类型)
因为我调用了 assign 我希望堆栈上没有剩余值(所以不是 returning 属性 本身)。
现在,如果我使用 SetMethod 分配 属性,例如:
public static Action PropertyAssign(object sourceObject, object destObject, PropertyInfo sourceProperty, PropertyInfo destProperty)
{
Expression source = Expression.PropertyOrField(
Expression.Constant(sourceObject), sourceProperty.Name);
Expression dest = Expression.PropertyOrField(
Expression.Constant(destObject), destProperty.Name);
Expression assign = Expression.Call(
Expression.Constant(destObject), destProperty.SetMethod, source);
Action assigner = (Action)Expression.Lambda(assign).Compile();
return assigner;
}
在这种情况下,函数 Lambda.Compile() return 是一个没有预期 parameter/return 值的操作。
所以这不是一个阻塞问题,但我只是好奇为什么赋值运算符 return 是一个值以及赋值 属性 (其中 Assign 应该只是调用 setter 方法)。
是否还有一种方法可以将第一次调用调整为 return 一个动作而不是一个函数?
你遇到的问题是因为赋值运算符实际上是一个 Func
,而 setter 有一个 void return.
通常我实际上会避免使用 Expression.Lambda
正是由于这个问题(以及转换)。
试试这个。
public static Action PropertyAssign(object sourceObject, object destObject,
PropertyInfo sourceProperty, PropertyInfo destProperty)
{
Expression source = Expression.Property(
Expression.Constant(sourceObject), sourceProperty);
Expression dest = Expression.Property(
Expression.Constant(destObject), destProperty);
Expression assign = Expression.Assign(dest, source);
return Expression.Lambda<Action>(assign).Compile();
}
这不会对您希望 IL 的委托类型产生任何歧义 return。
然而,这段特定的代码似乎完全没有意义,因为您不能重用生成的 IL。我建议您缓存它的参数化版本。
public delegate void Assign(TSource sourceObject, TDest destObject);
public static Assign PropertyAssign(TSource sourceObject, TDestdestObject,
PropertyInfo sourceProperty, PropertyInfo destProperty)
{
var sourceObjectExpression = Expression.Parameter(sourceObject);
var destPropertyExpression = Expression.Parameter(destProperty);
Expression source = Expression.Property(
sourceObjectExpression, sourceProperty);
Expression dest = Expression.Property(
destPropertyExpression, destProperty);
Expression assign = Expression.Assign(dest, source);
var lambda = Expression.Lambda<Assign>(
assign, sourceObjectExpression, destPropertyExpression);
return lambda.Compile();
}
我正在构建一个基于 属性 分配器的小型表达式。
这个想法很简单,只需创建一个获取一个对象 属性 并将其分配给另一个对象的 Action 属性。
所以如果我处理这个表达式:
public static Action PropertyAssign(object sourceObject, object destObject,
PropertyInfo sourceProperty, PropertyInfo destProperty)
{
Expression source = Expression.PropertyOrField(
Expression.Constant(sourceObject), sourceProperty.Name);
Expression dest = Expression.PropertyOrField(
Expression.Constant(destObject), destProperty.Name);
Expression assign = Expression.Assign(dest, source);
return (Action)Expression.Lambda(assign).Compile();
}
并尝试调用它,我得到一个异常告诉 Expression.Lambda 是 Func 类型(其中 T 是 属性 类型)
因为我调用了 assign 我希望堆栈上没有剩余值(所以不是 returning 属性 本身)。
现在,如果我使用 SetMethod 分配 属性,例如:
public static Action PropertyAssign(object sourceObject, object destObject, PropertyInfo sourceProperty, PropertyInfo destProperty)
{
Expression source = Expression.PropertyOrField(
Expression.Constant(sourceObject), sourceProperty.Name);
Expression dest = Expression.PropertyOrField(
Expression.Constant(destObject), destProperty.Name);
Expression assign = Expression.Call(
Expression.Constant(destObject), destProperty.SetMethod, source);
Action assigner = (Action)Expression.Lambda(assign).Compile();
return assigner;
}
在这种情况下,函数 Lambda.Compile() return 是一个没有预期 parameter/return 值的操作。
所以这不是一个阻塞问题,但我只是好奇为什么赋值运算符 return 是一个值以及赋值 属性 (其中 Assign 应该只是调用 setter 方法)。
是否还有一种方法可以将第一次调用调整为 return 一个动作而不是一个函数?
你遇到的问题是因为赋值运算符实际上是一个 Func
,而 setter 有一个 void return.
通常我实际上会避免使用 Expression.Lambda
正是由于这个问题(以及转换)。
试试这个。
public static Action PropertyAssign(object sourceObject, object destObject,
PropertyInfo sourceProperty, PropertyInfo destProperty)
{
Expression source = Expression.Property(
Expression.Constant(sourceObject), sourceProperty);
Expression dest = Expression.Property(
Expression.Constant(destObject), destProperty);
Expression assign = Expression.Assign(dest, source);
return Expression.Lambda<Action>(assign).Compile();
}
这不会对您希望 IL 的委托类型产生任何歧义 return。
然而,这段特定的代码似乎完全没有意义,因为您不能重用生成的 IL。我建议您缓存它的参数化版本。
public delegate void Assign(TSource sourceObject, TDest destObject);
public static Assign PropertyAssign(TSource sourceObject, TDestdestObject,
PropertyInfo sourceProperty, PropertyInfo destProperty)
{
var sourceObjectExpression = Expression.Parameter(sourceObject);
var destPropertyExpression = Expression.Parameter(destProperty);
Expression source = Expression.Property(
sourceObjectExpression, sourceProperty);
Expression dest = Expression.Property(
destPropertyExpression, destProperty);
Expression assign = Expression.Assign(dest, source);
var lambda = Expression.Lambda<Assign>(
assign, sourceObjectExpression, destPropertyExpression);
return lambda.Compile();
}