[英]C# Type Inference Gets the Wrong Type
我創建了以下屬性,如果在ViewState[TOTAL_RECORD_COUNT]
為null
時訪問了getter,則會拋出InvalidCastException
。
public long TotalRecordCount
{
get { return (long)(ViewState[TOTAL_RECORD_COUNT] ?? -1); }
set { ViewState[TOTAL_RECORD_COUNT] = value; }
}
我的想法是它錯誤地嘗試將ViewState[TOTAL_RECORD_COUNT]
的對象取消裝入一個int
,因為它包含一個long
而失敗,但我認為這個邏輯可能存在缺陷。 我將把它作為練習留給讀者指出這個缺陷。
我已經改變了那個屬性來閱讀
public long TotalRecordCount
{
get { return (long?)ViewState[TOTAL_RECORD_COUNT] ?? -1; }
set { ViewState[TOTAL_RECORD_COUNT] = value; }
}
這只是膨脹。 不過,我仍然想知道我的原始版本有什么問題... StackOverflow救援?
請注意,如果我嘗試在立即窗口中執行(long)(ViewState[TOTAL_RECORD_COUNT] ?? -1)
,我收到錯誤消息Cannot unbox 'ViewState[TOTAL_RECORD_COUNT] ?? -1' as a 'long'
Cannot unbox 'ViewState[TOTAL_RECORD_COUNT] ?? -1' as a 'long'
,如果我執行(ViewState[TOTAL_RECORD_COUNT] ?? -1).GetType().Name
我得到Int32
。 我可以執行(long)-1
並以-1作為Int64
...所以這是什么?
ViewState
索引器的返回類型是Object
(我假設你的意思是ASP.NET viewstate)。 現在考慮一下編譯器在看到它時必須做什么(這相當於你的代碼):
object o = ViewState[...];
var x = o ?? -1;
它必須推導出表達式的結果類型o ?? -1
o ?? -1
不知何故。 在左邊它看到一個object
,在右邊是一個int
。 顯然,這個表達式的最常見類型也是object
。 但是,這意味着如果它實際上最終使用-1
(因為o
為null),則必須將其轉換為object
- 對於int
,這意味着裝箱。
所以x
是object
類型,它可能包含一個int
(也許還有一些其他整數類型 - 我們不知道你的viewstate中有什么,例如它可能很short
)。 現在你寫:
long y = (long)x;
由於x
是object
,因此這是拆箱。 但是,您只能將值類型拆分為完全相同的類型(唯一的例外是您可以將簽名類型替換為等效的無符號類型,並將枚舉替換為其基礎類型)。 也就是說,你不能將unbox int
轉換為long
。 一個更簡單的方法來重現這個,沒有“額外”代碼,將是:
object x = 123;
long y = (long)x;
這也會拋出InvalidCastException
,並且出於同樣的原因。
演員必須只是一步。
表達式<object> ?? <int>
<object> ?? <int>
將產生另一個對象,當第一個值為null時,即。 ViewState[TOTAL_RECORD_COUNT]
為null,然后結果值將是一個對象,其中包含一個帶盒的Int32。
由於無法將包含Int32的對象解包為long,因此需要首先將其解包到Int32,然后將其轉換為long。
在你原版中,如果你把它分解,你就是這么做的:
(ViewState[TOTAL_RECORD_COUNT] ?? -1)
null-coalescing運算符(??)專門設計用於:
為可空值類型和引用類型定義默認值。
在您的情況下,您正在使用它來處理System.Object,因此它將采用您的“-1”,將其視為Int32,並將其裝入新的System.Object。 然后,它嘗試將Int32解包為long,這會失敗,因為強制轉換不能取消裝箱並在一個步驟中更改類型。
您可以通過使用L后綴指定-1為long來輕松解決此問題:
public long TotalRecordCount
{
get { return (long)(ViewState[TOTAL_RECORD_COUNT] ?? -1L); }
set { ViewState[TOTAL_RECORD_COUNT] = value; }
}
問題不在於ViewState[TOTAL_RECORD_COUNT]
的取消裝箱ViewState[TOTAL_RECORD_COUNT]
,問題是-1的裝箱和拆箱。
ViewState[TOTAL_RECORD_COUNT] ?? -1
你正在使用?? “對象”和“int”上的運算符。 結果類型是“對象”。 這意味着當視圖狀態中不存在該字段時,-1將被裝箱(作為int)。
然后,當程序嘗試將(int)-1解包為long時,程序會崩潰。
Int64是一個值類型,因此將null
轉換為值類型將始終拋出異常( NullReferenceException
)。 並且將Int32轉換為Int64將成功,並且不會拋出InvalidCastException
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.