简体   繁体   中英

Casting with 'as' - why doesn't this work?

Maybe it's just too early in the morning and I'm being an idiot, but I'm a bit confused by this....

SqlCommand cmd = new SqlCommand("prc_FooBar", conn));
object obj = cmd.ExecuteScalar();

 // this is fine
decimal? d = (decimal?)(obj as double?);

// this doesn't compile
decimal? d = (obj as double?) as decimal?; 

Why doesn't the last version compile?

The as operator is not the same as a cast. This blog explains:

http://blogs.msdn.com/b/csharpfaq/archive/2004/03/12/what-s-the-difference-between-cast-syntax-and-using-the-code-as-code-operator.aspx

It only "casts" between types in the same hierarchy, basically following the "is-a" idea. A decimal? is not a double? , but the compiler can trick you into thinking it can be when you (decimal?)myDouble; because it is explicitly casting it for you with the loss of information. The as operator does not do this for you and thus fails.

Update: you ask why there is a compiler error as opposed to a null result. This is because the as operator can never conceivably get double? to decimal? . Try:

string s = "";
MyClass f = s as MyClass;

Out of the box, this doesn't work because the compiler knows this. It is better to get a compiler error because it can never work in it's current state.

Under normal usage, the as operator can be used to forward cast base types into derived types if the type is actually the type you think it is. However, the type could be another derived type (this compiles):

MyBase b = new MyDerived1();
MyDerived2 d = b as MyDerived2();

Although the compiler technically could know this (in some situations), if it doesn't it responds with null if the cast fails.

I'm sure someone is about to come along and tell me how wrong I am :-)

From the docs :

... the as operator only performs reference conversions and boxing conversions.

Converting from double? to decimal? doesn't fit either of these categories, since there is no boxing going, and double? isn't a subtype or supertype of decimal? .

var x = v as X is equivalent to:

var v = v is X ? (X)v : null; but with only a single type-checking operation happening ( (X)v on its own checks that v is, or can be cast to, X and throws an exception otherwise).

Your latter case is equivalent to:

double? tmp = obj is double? ? (double?)obj : null;
decimal? d = tmp is decimal? ? (decimal?)tmp : null;

It's known at compile-time that tmp is a double? (with either a value, or no value making it equivalent to null ). The test of tmp is decimal? is therefore always false, and the operation fails at compile time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM