【问题标题】:Expression.Convert within Expression.TryCatchExpression.TryCatch 中的 Expression.Convert
【发布时间】:2017-05-11 06:59:41
【问题描述】:

我正在尝试向 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,并显示消息“catch 的主体必须与 try 的主体具有相同的类型”。我在这里做错了什么?我是否需要在 Catch 表达式中创建一个 Block 来“返回”一些虚拟值,即使它不会因为 Throw 而被命中?

还是我以完全错误的方式处理这个问题?

【问题讨论】:

  • 我当然会尝试将两者都包装在 Expression.Block 中,因为这样可以更准确地反映您试图概括的代码。

标签: c# expression-trees


【解决方案1】:

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

使用Expressions,它的工作方式有点不同:每个表达式都有一个返回类型,在TryCatch的情况下,try的返回类型Expression必须与返回相同任何catch Expressions 的类型。

在你的情况下,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 的类型在概念上更清晰,因为您实际上并不想从整个表达式中返回任何内容。

【讨论】:

  • 啊,好多了。将删除我的答案。
  • @jon-skeet 和 svick 非常感谢你们俩;将人的头绕在表达式周围需要一些时间来适应!由于 C# vs Expression 返回类型的解释而接受 svick 作为答案,这有助于澄清我在概念上从一个到另一个“翻译”的困惑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-26
相关资源
最近更新 更多