|
Great link, Guffa!
One further question, I read the link and find there is a comment like this -- "Notice that if you remove the initializer from Sat=1, the result will be ...", my confusion is in the related sample, are there any Enum element named Sat?
regards,
George
|
|
|
|
|
George_George wrote: I read the link and find there is a comment like this -- "Notice that if you remove the initializer from Sat=1, the result will be ...", my confusion is in the related sample, are there any Enum element named Sat?
It's referring to the first example:
enum Days {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};
If you remove =1 from the Sat element, it will get the default value 0 instead of 1.
Despite everything, the person most likely to be fooling you next is yourself.
|
|
|
|
|
Correct, thanks Guffa!
regards,
George
|
|
|
|
|
Because everything is a pointer in .Net. Despite being an int, i could very well point to an "object", and the compiler really doesn't have any way of knowing that you're being stupid.
What you should have done was:
int i = 100;
object b = (object)i;
long l = (long)b;
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997 ----- "...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001
|
|
|
|
|
|
John Simmons / outlaw programmer wrote: What you should have done was:
int i = 100;
object b = (object)i;
long l = (long)b;
No, that's not what he should have done. That doesn't differ anything at all from the original code. All you have done is to replace the implicit cast to object with an explicit cast, which produces exactly the same code as before.
This is what he should have done:
int i = 100;
object b = i;
long l = (int)b;
Despite everything, the person most likely to be fooling you next is yourself.
|
|
|
|
|
Nope - it'll still fail. See my next reply to him in this thread.
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997 ----- "...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001
|
|
|
|
|
John Simmons / outlaw programmer wrote: Nope - it'll still fail.
Now you don't make sense. Try the code that I posted, and you'll see that it works.
Despite everything, the person most likely to be fooling you next is yourself.
|
|
|
|
|
I did, and it aborts in the debugger.
The only way it would work is to cast using Convert.ToIn32 (which is a lot safer anyway).
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997 ----- "...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001
|
|
|
|
|
John Simmons / outlaw programmer wrote: I did, and it aborts in the debugger.
That sounds strange...
Aborts? What is that exactly? An exception?
I tried the code both in VS 2005 (C# 2.0) and VS 2008 (C# 3.0), and I can't get it to fail.
John Simmons / outlaw programmer wrote: The only way it would work is to cast using Convert.ToIn32
That doesn't make sense. Why would it not be possible to unbox an int?
Despite everything, the person most likely to be fooling you next is yourself.
|
|
|
|
|
Thanks Guffa,
1.
I have tried that it works because b will be unboxed to a temporary int, then int will be converted to long -- which are all legal, right?
2.
When we unbox a value type, we could only unbox to the exact original type, any other types allowed?
regards,
George
|
|
|
|
|
George_George wrote: I have tried that it works because b will be unboxed to a temporary int, then int will be converted to long -- which are all legal, right?
Yes. You can use implicit conversion from int to long:
long l = (int)b;
Or you can use explicit conversion from int to long:
long l = (long)(int)b;
George_George wrote: When we unbox a value type, we could only unbox to the exact original type, any other types allowed?
You can unbox to the actual type, or any (non-abstract) base type.
Despite everything, the person most likely to be fooling you next is yourself.
|
|
|
|
|
Sorry for my limited knowledge, Guffa!
I have tried to write some code to test your idea "You can unbox to the actual type, or any (non-abstract) base type.", I tried to write a struct, and write another struct to derives from it. It seems in C# it is not supported to have a struct inherits from another struct?
regards,
George
|
|
|
|
|
It's perfectly valid to cast an object to long.
Sure, in trivial cases like this, the compiler could do data-flow analysis; see that b is a boxed int and report a failure when unboxing it to long.
But do you want to make a certain kind of data-flow analysis mandatory for C# compilers?
Either you need to make the C# specifications extremely complex, or you need to make a C# compiler that violates the specification (since it would reject your program that is specified to fail at runtime, not at compile time).
|
|
|
|
|
Thanks Daniel,
It is ok for me the compiler does not check the data flow. My question is, I want to know what C# compiler check for type conversion (even if it is simple and can not find all the issues until runtime, I want to know the rules). Any ideas?
regards,
George
|
|
|
|
|
Part of the confusion here is that "(Type)expression" can have many meanings:
- type conversion
- unboxing
- boxing
- cast
What it means depends on the type of "expression" (the source type) and the type in the parenthesis (the target type).
If there is a conversion operator that converts from source type to target type, then that is used.
So "(long)an_int_variable" works because there is an conversion operator that sign-extends a 32-bit int to a 64-bit long.
Otherwise, if the source type is System.Object (or an interface) and the target type, then unboxing is used. Unboxing "unpacks" the value from box object. The box object must have exactly the correct type for this to work, otherwise you get an InvalidCastException at runtime.
If the source type is a value type and the target type is System.Object (or an interface implemented by that value type), then boxing is used. This means that a new object is created and the value is copied into it.
Otherwise, it's a cast; which basically means that a pointer is re-interpreted to point to a different object type. In this case, no conversion and no object creation happens.
You get a compile time error only if the compiler can see, by looking at source type and target type ONLY, that the conversion/cast would ALWAYS fail.
|
|
|
|
|
Thanks Daniel,
Great reply! Two more comments,
1.
What is the differences between conversion and cast?
2.
When we unbox an object, it must be the same type of the original value type or could be different in some situations?
regards,
George
|
|
|
|
|
Here are some examples:
int -> long: compiles, can never fail at runtime
int -> object -> long: compiles (int->object is valid boxing instruction, object->long is valid unboxing instruction), but always fails at runtime because a box containing int cannot be unboxed to long
int -> object -> int -> long: compiles and works at runtime
int -> IComparable -> int: same as int -> object -> int
int -> string: fails with compile error, there's no conversion operator int->string (ToString is not a conversion operator), and there's no way this cast could succeed
int -> object -> string: compiles (int->object is valid boxing instruction, object->string is valid cast), but always fails at run time because a boxed int cannot be cast to string.
long -> int: compiles, but might fail at runtime when the long is too large and integer overflow checking is enabled
|
|
|
|
|
Thanks Daniel,
1.
Daniel Grunwald wrote: overflow checking is enabled
Enable this in compile or runtime? How to enable it? (I did this in unmanaged C++ before, but never did this in C# because I think C# will always check overflow.)
2.
Previously, I think object is the base type for int/long/... such primitive types. But now I think we should not say object is the base type for int/long/... such primitive types, it should be called boxing to object, right?
3.
int --> string does not work, because we can only box to object? Not box to other types?
regards,
George
|
|
|
|
|
What you did is perfectly okay with the compiler (sometimes you can't rely on automated systems - you simply have to "do it right"). If you had used the correct casting mechanism, it would have been fine. I almost never use (long)varName to cast. Instead, I use Convert.ToIn32(varName) , which in your case would have yielded the expected value (100).
One other thing to remember - ALWAYS put a try/catch block around a Convert method, even if you simply eat the exception. You don't want your app crashing ungracefully.
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997 ----- "...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001
|
|
|
|
|
Thanks John,
Good to learn Convert class from you. But should we use Convert.ToInt64 to convert to a long?
regards,
George
|
|
|
|
|
No. Int32 is a long (in the traditional sense of the type).
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass..." - Dale Earnhardt, 1997 ----- "...the staggering layers of obscenity in your statement make it a work of art on so many levels." - Jason Jystad, 10/26/2001
|
|
|
|
|
John Simmons / outlaw programmer wrote: No. Int32 is a long (in the traditional sense of the type).
But we are not using the "traditional sense of the type". We are using C#, where the types are defined as:
int = System.Int32<br />
long = System.Int64
MSDN Library: Built-In Types[^]
Despite everything, the person most likely to be fooling you next is yourself.
|
|
|
|
|
Good to learn, thanks Guffa!
regards,
George
|
|
|
|
|
Compiler doesn't look at its value. Compiler just look at b's type. 'b' is casting to long, b is an object; So it allows to do it as it doesn't look at b's value.
Charith Jayasundara
|
|
|
|
|