在表达式树内部使用隐式转换运算符

问题描述 投票:0回答:1

假设我具有隐式转换运算符的以下类型:

public readonly struct WrappedInt
{
    public WrappedInt(int value)
    {
        Value = value;
    }

    public int Value { get; }

    public static implicit operator int (WrappedInt wrapper) => wrapper.Value;
}

然后是一个应用程序:

var wrapper = new WrappedInt(42);
int x1 = Unwrap(wrapper);
int x2 = UnwrapUsingExpression(wrapper);

private static int Unwrap(WrappedInt wrapper)
{
    int result = wrapper;
    return result;
}

private static int UnwrapUsingExpression(WrappedInt wrapper)
{
    var wrapperParameterExpression = Expression.Parameter(typeof(WrappedInt), "wrapper");
    var resultVariableExpression = Expression.Variable(typeof(int), "result");

    Expression right = wrapperParameterExpression;     // THIS is important
    var assignExpression = Expression.Assign(resultVariableExpression, right);
    var blockExpression = Expression.Block(
        new ParameterExpression[] { resultVariableExpression },
        new Expression[] { resultVariableExpression, assignExpression, resultVariableExpression }
    );

    var unwrapFunc = Expression.Lambda<Func<WrappedInt, int>>(blockExpression, wrapperParameterExpression).Compile();
    return unwrapFunc(wrapper);
}

[请注意,在Unwrap函数中,我使用隐式转换运算符执行int result = wrapper;-很好。

现在我想在表达式树中执行相同的操作-UnwrapWithExpression例程。在这里,我使用

将“结果”变量直接分配给“包装器”参数

Expression right = wrapperParameterExpression;

但是这不起作用-我收到了运行时异常:

System.ArgumentException:'类型'WrappedInt'的表达式不能用于分配给'System.Int32'类型。

我知道如何解决它,基本上可以访问Value属性:

Expression right = Expression.Property(wrapperParameterExpression, nameof(WrappedInt.Value));

或进行转换:

Expression right = Expression.Convert(wrapperParameterExpression, typeof(int));

但是为什么我不能简单地使用原始的直接分配并让我的隐式运算符来完成工作?

c# expression-trees implicit-conversion
1个回答
0
投票

表达式在很多方面都比C#更具限制性,尤其是在隐式类型转换方面。您会发现在许多情况下C#编译器会为您插入类型转换,但是您需要添加显式的Expression.Convert

如果要调用隐式转换方法,则需要添加Expression.Convert。无论是好是坏,表情都是这样工作的。这样做不是解决方法。

如果编写表达式:

Expression<Func<WrappedInt, int>> convert = x => x;

然后在调试器中查看convert.DebugView,您会看到以下内容:

.Lambda #Lambda1<System.Func`2[WrappedInt,System.Int32]>(WrappedInt $x) {
    (System.Int32)$x
}

(System.Int32)$xConvert节点(可以通过在调试器中查看convert.Body进行验证)。编译器决定,与Expressions中的C#最好的等效项是Expression.Convert,因此您也应该这样做。

© www.soinside.com 2019 - 2024. All rights reserved.