题
我创建了以下属性,它引发了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
...所以这是怎么回事?
解决方案
ViewState
索引器的返回类型为Object
(我假设你的意思是ASP.NET视图状态在这里)。现在考虑什么样的编译器有它看到这个的时候(这相当于你的代码)做:
object o = ViewState[...];
var x = o ?? -1;
它具有以某种方式推断表达o ?? -1
的结果类型。在左边它看到一个object
,右边是一个int
。显然,对于这种表达最一般的类型也object
。然而,这意味着,如果它实际上结束了使用-1
(因为o
为空)时,它必须把它转换为object
- 以及用于int
,这意味着拳击
所以x
的类型是object
的,并且它可以包含一个int
(也许还有一些其他的整数类型 - 我们不知道什么是在你的浏览状态,它可以被short
,例如)。现在,你写的:
long y = (long)x;
由于x
是object
,这是取消装箱。然而,你只能拆箱值类型为类型完全相同的(唯一的例外是,你可以替代等效的无符号类型作为它的底层基类型有符号类型和enum)。也就是说,你不能拆箱int
到long
。一个简单得多的方式来摄制,既没有“额外”的代码,将是:
object x = 123;
long y = (long)x;
其中也抛出InvalidCastException
,以及用于精确相同的原因。
其他提示
一个铸造必须是唯一的一个步骤。
在表达式<object> ?? <int>
会产生另一个对象,并且当所述第一值为空,即。 ViewState[TOTAL_RECORD_COUNT]
为空,然后将所得的值将是一个对象,具有一个装箱的Int32在它
由于不能拆箱含有一个Int32到长的对象,则需要首先将其拆箱为Int32,然后将其转换为长。
在问题不是ViewState[TOTAL_RECORD_COUNT]
的开箱,问题是-1的装箱和取消装箱。
ViewState[TOTAL_RECORD_COUNT] ?? -1
您正在使用??运营商“对象”和“INT”上。将得到的类型是“对象”。这意味着-1将盒装(如INT)当该字段不视图状态存在。
然后程序崩溃后,当它试图拆箱(INT)-1作为长。
在你原来的,如果你打破它,你正在做的:
(ViewState[TOTAL_RECORD_COUNT] ?? -1)
在空合并运算符(?)是specifially设计成:
,以限定用于的空值类型强>以及<强>引用类型的默认值。强>
在你的情况,你用它来处理一个System.Object,所以要采取你的“-1”,把它作为一个Int32,和盒子到一个新System.Object的。然后,尝试将的Int32拆箱成长,这将失败,因为铸造不能拆箱和在单一步骤中改变的类型。
可以通过指定的-1是一个长期通过使用L后缀容易解决这个问题:
public long TotalRecordCount
{
get { return (long)(ViewState[TOTAL_RECORD_COUNT] ?? -1L); }
set { ViewState[TOTAL_RECORD_COUNT] = value; }
}
的Int64 是值类型,所以铸造null
值类型总是会抛出异常(NullReferenceException
)。铸造一个Int32到Int64的会成功,会不会引发InvalidCastException
。