我試圖將一些錯誤處理添加到Effort庫中的代碼塊,該代碼塊生成表達式樹以執行轉換並將該結果分配給屬性。
現有代碼的問題是,當嘗試將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而永遠不會被擊中?
或者我是以完全錯誤的方式接近這個?
在普通的C#代碼中,一個方法作為一個整體必須返回一個值或拋出異常。
使用Expression
s,它的工作方式有所不同:每個表達式都有一個返回類型,在TryCatch
的情況下, try
Expression
的返回類型必須與任何catch
Expression
的返回類型相同。
在您的情況下, try
的類型是int
,但catch
的類型是void
,因此它們不能一起使用。要解決此問題,您需要將try
的類型更改為void
,或者將catch
的類型更改為int
。
要將try
的類型更改為void
,可以使用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
表達式,任何返回類型都可以是有效的(因為它實際上不返回), 有一個重載允許您指定返回類型 :
Expression.TryCatch(
Expression.Assign(…),
Expression.Catch(
typeof(NullReferenceException),
Expression.Throw(
Expression.Constant(
new InvalidOperationException("Unhandled exception")),
typeof(int))))
我認為改變try
的類型在概念上更清晰,因為你實際上並不想從整個表達式返回任何東西。