2

次のプロパティを作成しました。これは、がであったときにInvalidCastExceptionゲッターにアクセスした場合にスローします。ViewState[TOTAL_RECORD_COUNT]null

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'(ViewState[TOTAL_RECORD_COUNT] ?? -1).GetType().NameくださいInt32。私は実行(long)-1して、最終的に-1として終わることができInt64ます...それで、どうしたのですか?

4

5 に答える 5

13

ViewStateインデクサーの戻り値のタイプは次のObjectとおりです(ここではASP.NETビューステートを意味すると思います)。ここで、コンパイラがこれを確認したときに何をしなければならないかを考えてみましょう(これはあなたのコードに相当します):

object o = ViewState[...];
var x = o ?? -1;

o ?? -1どういうわけか、式の結果タイプを推測する必要があります。左側にはがobject表示され、右側にはが表示されintます。明らかに、この式の最も一般的なタイプはobjectです。ただし、これは、実際にそれを使用することになった場合-1onullであったため)、それをobject-に変換する必要があることを意味します。また、のint場合、これはボクシングを意味します。

したがってx、はタイプobjectであり、(および他の整数タイプも含まれる可能性があります。たとえばint、ビューステートに何があるかはわかりませんshort)。今あなたは書く:

long y = (long)x;

なので、これは開箱xです。objectただし、値型を完全に同じ型にボックス化解除することしかできません(唯一の例外は、符号付き型を同等の符号なし型に置き換え、その基になる基本型を列挙型に置き換えることができることです)。つまり、にボックスを解除intすることはできませんlong。「余分な」コードを使用せずにこれを再現するはるかに簡単な方法は、次のとおりです。

object x = 123;
long y = (long)x;

これもスローInvalidCastExceptionしますが、まったく同じ理由で。

于 2009-10-01T20:18:34.433 に答える
5

キャストは1ステップだけである必要があります。

<object> ?? <int>は別のオブジェクトを生成し、最初の値がnullの場合、つまり。ViewState[TOTAL_RECORD_COUNT]nullの場合、結果の値は、ボックス化されたInt32を含むオブジェクトになります。

Int32を含むオブジェクトをlongにアンボックス化することはできないため、最初にInt32にボックス化を解除してから、longにキャストする必要があります。

于 2009-10-01T20:11:12.030 に答える
1

オリジナルでは、それを分解すると、次のようになります。

(ViewState[TOTAL_RECORD_COUNT] ?? -1)

null合体演算子(??)は、特に次のように設計されています。

null許容値型参照型のデフォルト値を定義します。

あなたの場合、それを使用してSystem.Objectを処理しているので、「-1」を取り、それをInt32として扱い、新しいSystem.Objectにボックス化します。次に、Int32をlongにアンボックス化しようとしますが、キャストは1つのステップでボックス化を解除してタイプを変更できないため、失敗します。

これは、Lサフィックスを使用して-1が長いことを指定することで簡単に解決できます。

public long TotalRecordCount
{
    get { return (long)(ViewState[TOTAL_RECORD_COUNT] ?? -1L); }
    set { ViewState[TOTAL_RECORD_COUNT] = value; }
}
于 2009-10-01T20:06:38.833 に答える
1

問題は、のボックス化解除ではなくViewState[TOTAL_RECORD_COUNT]、-1のボックス化とボックス化解除です。

   ViewState[TOTAL_RECORD_COUNT] ?? -1

あなたは??を使用しています 「object」と「int」の演算子。結果のタイプは「オブジェクト」です。これは、フィールドがビューステートに存在しない場合、-1が(intとして)ボックス化されることを意味します。

その後、(int)-1をlongとしてアンボックス化しようとすると、プログラムがクラッシュします。

于 2009-10-01T20:08:59.270 に答える
0

Int64は値型であるため、値型にキャストnullすると常に例外(NullReferenceException)がスローされます。また、Int32をInt64にキャストすると成功し、。はスローされませんInvalidCastException

于 2009-10-01T20:04:46.457 に答える