C#类型推断获取错误的类型

Chr*_*uts 2 c# unboxing casting

我创建了以下属性,它抛出InvalidCastException,如果当吸气剂访问ViewState[TOTAL_RECORD_COUNT]null.

public long TotalRecordCount
{
    get { return (long)(ViewState[TOTAL_RECORD_COUNT] ?? -1); }
    set { ViewState[TOTAL_RECORD_COUNT] = value; }
}
Run Code Online (Sandbox Code Playgroud)

我的想法是它错误地尝试将对象拆箱ViewState[TOTAL_RECORD_COUNT]到一个int,因为它包含了一个失败long,但我认为这个逻辑可能存在缺陷.我将把它作为练习留给读者指出这个缺陷.

我已经改变了那个属性来阅读

public long TotalRecordCount
{
    get { return (long?)ViewState[TOTAL_RECORD_COUNT] ?? -1; }
    set { ViewState[TOTAL_RECORD_COUNT] = value; }
}
Run Code Online (Sandbox Code Playgroud)

这只是膨胀.不过,我仍然想知道我的原始版本有什么问题... 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......所以这是什么?

Pav*_*aev 13

ViewState索引器的返回类型是Object(我假设你的意思是ASP.NET viewstate).现在考虑一下编译器在看到它时必须做什么(这相当于你的代码):

object o = ViewState[...];
var x = o ?? -1;
Run Code Online (Sandbox Code Playgroud)

它必须以o ?? -1某种方式推断表达式的结果类型.在左边它看到一个object,在右边是一个int.显然,这个表达式的最常见类型也是object.但是,这意味着如果它实际上最终使用它-1(因为o为null),它将必须将其转换为object- 并且对于一个int,这意味着拳击.

x类型也是如此object,它可能包含一个int(也许还有一些其他整数类型 - 我们不知道你的视图状态是什么short,例如它可能是).现在你写:

long y = (long)x;
Run Code Online (Sandbox Code Playgroud)

由于xIS object,这是拆箱.但是,您只能将值类型拆分为完全相同的类型(唯一的例外是您可以将签名类型替换为等效的无符号类型,并将枚举替换为其基础类型).也就是说,你不能拆箱intlong.一个更简单的方法来重现这个,没有"额外"代码,将是:

object x = 123;
long y = (long)x;
Run Code Online (Sandbox Code Playgroud)

哪个也抛出InvalidCastException,并且出于同样的原因.


ang*_*son 5

演员必须只是一步.

表达式<object> ?? <int>将产生另一个对象,当第一个值为null时,即.ViewState[TOTAL_RECORD_COUNT]如果为null,则结果值将是一个对象,其中包含一个带盒的Int32.

由于无法将包含Int32的对象解包为long,因此需要首先将其解包到Int32,然后将其转换为long.