我正在尝试向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而永远不会被命中?
或者我是以完全错误的方式接近这个?
答案 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
的类型在概念上更清晰,因为您实际上并不想从整个表达式返回任何内容。