Expression.Convert中的Expression.Convert

时间:2013-01-16 18:23:28

标签: c# expression-trees

我正在尝试向block of code in the Effort library添加一些错误处理,生成表达式树以执行转换并将结果分配给属性。

现有代码的问题是,在尝试将null赋值给具有值类型的属性时,在运行时调用此表达式时,会抛出NullReferenceException。在这种情况下,我没有关于它试图分配的属性的信息,所以我想抛出一个更具体的异常。

以下是我第一次尝试将此逻辑封装在try / catch块中,并在转换失败时抛出异常。最后我会向InvalidOperationException添加更多信息。

blockElements.Add(
    Expression.TryCatch(
        Expression.Assign(
            Expression.Property(result, this.Properties[i]),
            Expression.Convert(
                Expression.ArrayIndex(parameter, Expression.Constant(i)),
                this.Properties[i].PropertyType)),
        Expression.Catch(typeof(NullReferenceException),
            Expression.Throw(Expression.Constant(
            new InvalidOperationException("Unhandled exception"))))));

在我看来,这就是我想要做的事情:

try
{
    Property = (int)value;
}
catch (NullReferenceException)
{
    throw new InvalidOperationException("Unhandled exception");
}

但是在运行时,该表达式现在抛出一个ArgumentException,并显示消息“Body of catch必须与try主体具有相同的类型”。我在这做错了什么?我是否需要在Catch表达式中创建一个Block来“返回”一些虚拟值,即使它因为Throw而永远不会被命中?

或者我是以完全错误的方式接近这个?

1 个答案:

答案 0 :(得分:8)

在普通的C#代码中,一个方法作为一个整体必须返回一个值或抛出异常。

使用Expression s,它的工作方式有所不同:每个表达式都有一个返回类型,如果是TryCatch,则try Expression的返回类型必须与任何catch Expression s的返回类型相同。

在您的情况下,try的类型为int,但catch的类型为void,因此无法一起使用。要解决此问题,您需要将try的类型更改为void,或将catch的类型更改为int

要将try的类型更改为void,您可以使用an overload of Expression.Block()来指定块的类型(通常,它与最后一个类型相同)块中的表达式):

Expression.TryCatch(
    Expression.Block(
        typeof(void),
        Expression.Assign(…)),
    Expression.Catch(
        typeof(NullReferenceException),
        Expression.Throw(
            Expression.Constant(
                new InvalidOperationException("Unhandled exception")))))

要将catch的类型更改为int,您需要更改Throw表达式的类型。因为对于Throw表达式,任何返回类型都可以是有效的(因为它实际上不会返回),there is an overload that lets you specify the return type

Expression.TryCatch(
    Expression.Assign(…),
    Expression.Catch(
        typeof(NullReferenceException),
        Expression.Throw(
            Expression.Constant(
                new InvalidOperationException("Unhandled exception")),
            typeof(int))))

我认为更改try的类型在概念上更清晰,因为您实际上并不想从整个表达式返回任何内容。