使用Expression.Convert类型来转换Expression.Property。

3

我正在尝试转换参数表达式,但在将其转换为值类型时遇到了困难。以下是我的代码示例:

public static MemberExpression ConvertToType(ParameterExpression sourceParameter,
                                              PropertyInfo propertyInfo, 
                                              TypeCode typeCode)
{
    var sourceExpressionProperty = Expression.Property(sourceParameter, sourceProperty);

    //throws an exception if typeCode is a value type.
    Expression convertedSource = Expression.Convert(sourceExpressionProperty,
                                                Type.GetType("System." + typeCode));

    return convertedSource;
}

我收到了以下无效操作异常:
没有定义类型为“System.String”和“System.Decimal”的强制转换运算符。
任何有关此转换的帮助都将不胜感激。

2
“Convert” 基本上与 C# 强制转换相同。使用相同的规则。您将需要使用一些转换方法。 - leppie
3
иҜ·дҪҝз”ЁдёӢйқўжҸҗдҫӣзҡ„й“ҫжҺҘдёӯзҡ„Convert.ChangeTypeеҮҪж•°гҖӮдҪ жӢҘжңүжүҖжңүеҝ…иҰҒзҡ„дҝЎжҒҜгҖӮ - leppie
2
我在这方面遇到了一些麻烦。我的表达式功夫不够好。 - will
2
Expression.Call(typeof(Convert).GetMethod(...), sourceExpressionProperty, Expression.Quote(typecode)) - leppie
我找到了问题所在。在调用Convert.ChangeType时,我没有考虑到空值。 - will
显示剩余6条评论
2个回答

8
public class ExpressionUtils
{
    public static MethodCallExpression ConvertToType(
        ParameterExpression sourceParameter,
        PropertyInfo sourceProperty,
        TypeCode typeCode)
    {
        var sourceExpressionProperty = Expression.Property(sourceParameter, sourceProperty);
        var changeTypeMethod = typeof(Convert).GetMethod("ChangeType", new Type[] { typeof(object), typeof(TypeCode) });
        var callExpressionReturningObject = Expression.Call(changeTypeMethod, sourceExpressionProperty, Expression.Constant(typeCode));
        return callExpressionReturningObject;
    }
}

请注意,生成的表达式是对 Convert.ChangeType 方法的调用,该方法将返回 System.Object。
以下是一个单元测试:
[TestClass]
public class UnitTest1
{
    private class MyClass
    {
        public string ValueAsString { get; set; }
    }

    [TestMethod]
    public void TestMethod1()
    {
        var parameter = Expression.Parameter(typeof(MyClass));
        var property = typeof(MyClass).GetProperty("ValueAsString");
        var lambdaBody = ExpressionUtils.ConvertToType(parameter, property, TypeCode.Decimal);
        var lambda = Expression.Lambda<Func<MyClass, object>>(lambdaBody, parameter);
        var valueAsDecimal = (decimal) lambda.Compile().Invoke(new MyClass { ValueAsString = "42" });
        Assert.AreEqual(42m, valueAsDecimal);
    }
}

这更或多或少是我采用的方法,除了我处理了空值。 - will

1
我采用的解决方案是:
private static Expression GetConvertedSource(ParameterExpression sourceParameter,
                                             PropertyInfo sourceProperty, 
                                             TypeCode typeCode)
{
    var sourceExpressionProperty = Expression.Property(sourceParameter,
                                                       sourceProperty);

    var changeTypeCall = Expression.Call(typeof(Convert).GetMethod("ChangeType", 
                                                           new[] { typeof(object),
                                                            typeof(TypeCode) }),
                                                            sourceExpressionProperty,
                                                            Expression.Constant(typeCode)
                                                            );

    Expression convert = Expression.Convert(changeTypeCall, 
                                            Type.GetType("System." + typeCode));

    var convertExpr = Expression.Condition(Expression.Equal(sourceExpressionProperty,
                                            Expression.Constant(null, sourceProperty.PropertyType)),
                                            Expression.Default(Type.GetType("System." + typeCode)),
                                            convert);



    return convertExpr;
}

请注意使用 Expression.Condition 处理 null 值。

2
你应该接受另一个答案并编辑它以包括空值检查,因为他指引了你正确的方向。 - jgauffin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接