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

时间:2009-10-01 20:02:24

标签: c# casting unboxing

我创建了以下属性,如果在InvalidCastExceptionViewState[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 ...那么这是什么?

5 个答案:

答案 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;

由于xobject,因此这是拆箱。但是,您只能将值类型拆分为完全相同的类型(唯一的例外是您可以将签名类型替换为等效的无符号类型,并将枚举替换为其基础类型)。也就是说,您无法将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