生成 Expression.Assign 设置小数时出现异常?从十进制
Exception when generating Expression.Assign to set decimal? from decimal
我 运行 在构建表达式时遇到了一个有趣的问题。我进行了一些基本的类型强制检查,以确保完成最少的转换,但是,我 运行 遇到了一个我没想到的问题。
当我尝试使用 Expression.Assign
生成 BinaryExpression
并且我从 decimal
转到 decimal?
时,我收到异常:
System.ArgumentException: 'Expression of type 'System.Decimal' cannot be used for assignment to type 'System.Nullable'1[System.Decimal]
有人可以解释一下吗?考虑以下评估为真:
typeof(decimal?).IsAssignableFrom(typeof(decimal))
预期的分配应等于以下语句:
decimal? x = null;
decimal y = 10;
x = y;
有问题的代码:
private Expression BuildMapExpressionForValueMap(MemberInfo destinationProperty, MemberInfo sourceProperty)
{
Expression assignmentExpression = Expression.PropertyOrField(_source, sourceProperty.Name);
Type destinationType = destinationProperty.GetUnderlyingType();
if (!destinationType.IsAssignableFrom(sourceProperty.GetUnderlyingType()))
{
assignmentExpression = BuildCastExpression(assignmentExpression, destinationType);
}
var expression = Expression.Assign(Expression.PropertyOrField(_destination, destinationProperty.Name)
, assignmentExpression);
return expression;
}
存在从不可空值类型到相应可空类型的隐式转换。您生成的表达式必须是显式的。与无法生成将 Int32 分配给 Int64 类型变量的表达式的原因相同。编译器显式生成转换调用,因此您不必这样做。试一试,你就会知道。
您必须添加转换。
var param = Expression.Variable(typeof(decimal?));
var value = Expression.Constant(20m, typeof(decimal));
var expr = Expression.Assign(param,
//value // fails
Expression.Convert(value, param.Type)
);
当您编写常规 C# 代码时,编译器会免费为您进行隐式转换。但是当你处理 Linq.Expressions
时,你应该明确定义每个类型转换。
检查这段代码,它分配一个 y
给 x
然后打印到控制台:
var paramX = Expression.Parameter(typeof(decimal?), "x");
var paramY = Expression.Parameter(typeof(decimal), "y");
var lambda = Expression.Lambda<Action<decimal?, decimal>>(
Expression.Block(
Expression.Assign(paramX, Expression.Convert(paramY, typeof(decimal?)))
, Expression.Call(typeof(Console), "WriteLine", new Type[0],
Expression.Convert(paramX, typeof(decimal)))
),
paramX, paramY);
lambda.Compile().Invoke(null, 10);
你可以找到一个演示 here
我 运行 在构建表达式时遇到了一个有趣的问题。我进行了一些基本的类型强制检查,以确保完成最少的转换,但是,我 运行 遇到了一个我没想到的问题。
当我尝试使用 Expression.Assign
生成 BinaryExpression
并且我从 decimal
转到 decimal?
时,我收到异常:
System.ArgumentException: 'Expression of type 'System.Decimal' cannot be used for assignment to type 'System.Nullable'1[System.Decimal]
有人可以解释一下吗?考虑以下评估为真:
typeof(decimal?).IsAssignableFrom(typeof(decimal))
预期的分配应等于以下语句:
decimal? x = null;
decimal y = 10;
x = y;
有问题的代码:
private Expression BuildMapExpressionForValueMap(MemberInfo destinationProperty, MemberInfo sourceProperty)
{
Expression assignmentExpression = Expression.PropertyOrField(_source, sourceProperty.Name);
Type destinationType = destinationProperty.GetUnderlyingType();
if (!destinationType.IsAssignableFrom(sourceProperty.GetUnderlyingType()))
{
assignmentExpression = BuildCastExpression(assignmentExpression, destinationType);
}
var expression = Expression.Assign(Expression.PropertyOrField(_destination, destinationProperty.Name)
, assignmentExpression);
return expression;
}
存在从不可空值类型到相应可空类型的隐式转换。您生成的表达式必须是显式的。与无法生成将 Int32 分配给 Int64 类型变量的表达式的原因相同。编译器显式生成转换调用,因此您不必这样做。试一试,你就会知道。
您必须添加转换。
var param = Expression.Variable(typeof(decimal?));
var value = Expression.Constant(20m, typeof(decimal));
var expr = Expression.Assign(param,
//value // fails
Expression.Convert(value, param.Type)
);
当您编写常规 C# 代码时,编译器会免费为您进行隐式转换。但是当你处理 Linq.Expressions
时,你应该明确定义每个类型转换。
检查这段代码,它分配一个 y
给 x
然后打印到控制台:
var paramX = Expression.Parameter(typeof(decimal?), "x");
var paramY = Expression.Parameter(typeof(decimal), "y");
var lambda = Expression.Lambda<Action<decimal?, decimal>>(
Expression.Block(
Expression.Assign(paramX, Expression.Convert(paramY, typeof(decimal?)))
, Expression.Call(typeof(Console), "WriteLine", new Type[0],
Expression.Convert(paramX, typeof(decimal)))
),
paramX, paramY);
lambda.Compile().Invoke(null, 10);
你可以找到一个演示 here