簡體   English   中英

C#類型推斷獲取錯誤的類型

[英]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 ,這意味着裝箱。

所以xobject類型,它可能包含一個int (也許還有一些其他整數類型 - 我們不知道你的viewstate中有什么,例如它可能很short )。 現在你寫:

long y = (long)x;

由於xobject ,因此這是拆箱。 但是,您只能將值類型拆分為完全相同的類型(唯一的例外是您可以將簽名類型替換為等效的無符號類型,並將枚舉替換為其基礎類型)。 也就是說,你不能將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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM