C # Output Type Gets Wrong Type

I created the following property which checked InvalidCastException

if the recipient was accessed when ViewState[TOTAL_RECORD_COUNT]

was null

.

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

      

My thought is that it was wrongly trying to unpack the object in ViewState[TOTAL_RECORD_COUNT]

to int

, which failed because it contained long

, but I think there might be a flaw in this logic. I'll leave this as an exercise for the reader to point out this error.

I have since changed this property to read

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

      

which only works swells. However, I am not interested in what was wrong with my original version ... StackOverflow help?

Please note that if I try to execute (long)(ViewState[TOTAL_RECORD_COUNT] ?? -1)

in the Immediate window I get an error Cannot unbox 'ViewState[TOTAL_RECORD_COUNT] ?? -1' as a 'long'

and if I execute (ViewState[TOTAL_RECORD_COUNT] ?? -1).GetType().Name

I get Int32

. I can execute (long)-1

and end up getting -1 like Int64

... so what's up?

+2


source to share


5 answers


The return type of the indexer ViewState

is Object

(I'm assuming you mean the view in the ASP.NET view here). Now let's look at what the compiler should do when it sees this (which is equivalent to your code):

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

      

It must somehow infer the type of the result of the expression o ?? -1

. On the left he sees Object

, on the right - int

. It is clear that the most common type of this expression is also Object

. However, this means that if it does end up with that -1

(because it o

was null) it will have to convert it to Object

- and for int

that means boxing.

So, it x

has a type Object

, and it can contain int

(and maybe some other integral type - we don't know what is in your view), it can be short

, for example). Now you write:



long y = (long)x;

      

Since x

Object

, this is unpacking. However, you can only use value types of type unbox in the same type (the only exception is that you can substitute the signature type for an equivalent unsigned type and enumerate its base type). That is, you cannot decompress int

into long

. An easier way to reproduce this, without the "extra" code, would be:

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

      

Which also throws out InvalidCastException

for the same reason.

+13


source


Listing should only be one step.

The expression <object> ?? <int>

will result in the creation of another object, and when the first value is null, i.e. ViewState[TOTAL_RECORD_COUNT]

is null, then the resulting value will be an object with an Int32 package nested inside it.



Since you cannot unbox an object containing an Int32, you need to unbox it to Int32 first and then convert it to long.

+5


source


In the original, if you broke it, you did:

(ViewState[TOTAL_RECORD_COUNT] ?? -1)

      

The null-coalescing operator (??) is specifically designed for:

to define a default value for null- valued types as well as reference types.

In your case, you are using it to handle System.Object, so it will take your "-1", treat it as Int32 and insert it into a new System.Object. Then it tries to unbox the Int32 into a long one, which fails because the cast cannot unbox and change the type in one step.

You can easily solve this by specifying that your -1 is long using the L suffix:

public long TotalRecordCount
{
    get { return (long)(ViewState[TOTAL_RECORD_COUNT] ?? -1L); }
    set { ViewState[TOTAL_RECORD_COUNT] = value; }
}

      

+1


source


The problem is not unpacking ViewState[TOTAL_RECORD_COUNT]

, the problem is boxing and unpacking -1. In the meantime, there is no need to know about it. ”

   ViewState[TOTAL_RECORD_COUNT] ?? -1

      

You're using?? operator on "object" and "int". The resulting type is "object". This means that -1 will be boxed (as an int) when the field does not exist in view state.

Then your program crashes later when it tries to unpack (int) -1 as long.

+1


source


Int64 is a value type, so casting null

to a value type will always throw an exception ( NullReferenceException

), AND casting an Int32 to Int64 will succeed and won't throw InvalidCastException

.

0


source







All Articles