我创建了以下属性,如果在InvalidCastException
为ViewState[TOTAL_RECORD_COUNT]
时访问了getter,则会抛出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
并以Int64
结束-1 ...那么这是什么?
答案 0 :(得分:13)
ViewState
索引器的返回类型是Object
(我假设你的意思是ASP.NET viewstate)。现在考虑一下编译器在看到它时所要做的事情(这相当于你的代码):
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
,因此这是拆箱。但是,您只能将值类型拆分为完全相同的类型(唯一的例外是您可以将签名类型替换为等效的无符号类型,并将枚举替换为其基础类型)。也就是说,您无法将int
取消装入long
。如果没有“额外”代码,重新编写此代码的更简单方法是:
object x = 123;
long y = (long)x;
其中也会抛出InvalidCastException
,并且出于同样的原因。
答案 1 :(得分:5)
演员必须只是一步。
表达式<object> ?? <int>
将产生另一个对象,当第一个值为null时,即。 ViewState[TOTAL_RECORD_COUNT]
为null,然后结果值将是一个对象,其中包含一个装箱的Int32。
由于无法将包含Int32的对象解包为long,因此需要首先将其解包到Int32,然后将其转换为long。
答案 2 :(得分:1)
在原版中,如果你将其分解,那你就是这样做的:
(ViewState[TOTAL_RECORD_COUNT] ?? -1)
null-coalescing operator (??)专门设计为:
定义可空值类型的默认值以及引用类型。
在您的情况下,您正在使用它来处理System.Object,因此它将采用您的“-1”,将其视为Int32,并将其装入新的System.Object。然后,它尝试将Int32解包成一个long,因为转换无法取消装箱并在一个步骤中更改类型。
您可以通过使用L后缀指定-1为长来轻松解决此问题:
public long TotalRecordCount
{
get { return (long)(ViewState[TOTAL_RECORD_COUNT] ?? -1L); }
set { ViewState[TOTAL_RECORD_COUNT] = value; }
}
答案 3 :(得分:1)
问题不在于ViewState[TOTAL_RECORD_COUNT]
的拆箱,问题是-1的装箱和拆箱。
ViewState[TOTAL_RECORD_COUNT] ?? -1
你正在使用?? “对象”和“int”上的运算符。结果类型是“对象”。这意味着当视图状态中不存在该字段时,-1将被装箱(作为int)。
然后,当程序试图将(int)-1取消装箱为长时,程序会崩溃。
答案 4 :(得分:0)
Int64是一种值类型,因此将null
强制转换为值类型将始终抛出异常(NullReferenceException
)。将Int32转换为Int64将成功,并且不会抛出InvalidCastException
。