C# Expression.Convert in Expression.TryCatch

C# Expression.Convert in Expression.TryCatch,c#,expression-trees,C#,Expression Trees,我正在尝试向生成表达式树以执行转换并将结果分配给属性的表达式添加一些错误处理 现有代码的问题是,当尝试将null分配给值类型为的属性时,在运行时调用此表达式时会引发NullReferenceException。在本例中,我没有关于它试图分配的属性的信息,因此我想抛出一个更具体的异常 下面是我第一次尝试将此逻辑封装在try/catch块中,并在转换失败时引发异常。最后,我将向InvalidOperationException添加更多信息 blockElements.Add( Express

我正在尝试向生成表达式树以执行转换并将结果分配给属性的表达式添加一些错误处理

现有代码的问题是,当尝试将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的Body必须与try的Body具有相同的类型”?我是否需要在Catch表达式中创建一个块来“返回”一些伪值,即使它不会因为抛出而被命中

还是我完全错误地处理了这个问题?

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

对于
Expression
s,它的工作原理有点不同:每个表达式都有一个返回类型,在
TryCatch
的情况下,
try
表达式的返回类型必须与任何
catch
表达式的返回类型相同

在您的例子中,
try
的类型是
int
,但是
catch
的类型是
void
,因此它们不能一起使用。要解决此问题,您需要将
try
的类型更改为
void
,或者将
catch
的类型更改为
int

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

要将
catch
的类型更改为
int
,您可能需要更改
Throw
表达式的类型。由于对于
Throw
表达式,任何返回类型都是有效的(因为它实际上不返回):


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

我当然会尝试将两者都包装在
表达式中。Block
,因为这将更准确地反映您试图重述的代码。啊,更好。将删除我的答案。@jon skeet和svick非常感谢你们两位;把自己的头绕在表达上需要一些时间去适应!接受svick作为答案,因为C#vs表达式返回类型的解释有助于澄清我在概念上从一个“翻译”到另一个的困惑。
Expression.TryCatch(
    Expression.Block(
        typeof(void),
        Expression.Assign(…)),
    Expression.Catch(
        typeof(NullReferenceException),
        Expression.Throw(
            Expression.Constant(
                new InvalidOperationException("Unhandled exception")))))
Expression.TryCatch(
    Expression.Assign(…),
    Expression.Catch(
        typeof(NullReferenceException),
        Expression.Throw(
            Expression.Constant(
                new InvalidOperationException("Unhandled exception")),
            typeof(int))))