why C# can't implicitly convert a long var to an object var then to ulong?
long a = 0;
Object c = a;
ulong b = (ulong)c; // throw exception here
you can only unbox to the exact same type as was boxed
Object c = a
boxes a which is a long
ulong b = (ulong)c;
tries to unbox c as a ulong but it is a long and hence fails.
ulong b = (ulong)((long)c);
would work since it unboxes c as a long. c being long this will work and you can cast long to ulong
If you box a value type T, you can only unbox it as itself or as a Nullable ( T? ).
Any other cast is invalid.
That's because a cast from object can never be interpreted as a conversion, whereas the is a conversion between long and ulong.
So this is legal:
var c = (long) b;
This is also legal:
var c = (long?) b;
But this is not:
var c = (ulong) b;
To do what you want to, you have to cast twice: the first is only unboxing, and the second is the actual conversion:
var c = (ulong)(long) b;
For further information, see this blog post by Eric Lippert.
All the above result in a loss of data if the value is greater than the maximum value of a long (9,223,372,036,854,775,807).
ulong has a minimum of zero and a maximum of 18,446,744,073,709,551,615.
To convert without this risk use
ulong b = Convert.ToUInt64(c);
Short and simple answer: beacuse long and ulong are not the same type. One is a signed long the other is an unsigned long.
Related
I can cast byte to int without any problems.
byte a = 2;
int b = a; // => unboxing, boxing or conversion?
When I cast byte first to object and then to int I get an InvalidCastException.
byte a = 2;
object b = a; // => boxing?
int c = (int) b; // => unboxing fails?
But I can workaround this problem by using Convert.ToInt32.
byte a = 2;
object b = a; // => boxing?
int c = Convert.ToInt32(b); // => what happens here?
Why do I get an InvalidCastException in the second example?
What does Convert.ToInt32 in the background?
Did I label boxing, unboxing and conversion correctly? / What is the correct term when in the examples where I'm not sure?
Are the conversion operators at play here? Is there an overview about the basic conversion operators of the basic types?
Please don't hesistate to hint me other things I might have gotten wrong or missed.
Why do I get an InvalidCastException in the second example?
Because you specified you want to cast (and at the same time unbox) the type of the (boxed) variable to something else. And there is no built-in, implicit or explicit conversion operator defined, so it fails.
What does Convert.ToInt32 in the background?
This. It uses the IConvertible interface to do the conversion.
Did I label boxing, unboxing and conversion correctly? / What is the correct term when in the examples where I'm not sure?
int b = a; // => conversion
object b = a; // => boxing
int c = (int) b; // => casting fails
int c = Convert.ToInt32(b); // => what happens here: a method call that happens to do a conversion
Are the conversion operators at play here? Is there an overview about the basic conversion operators of the basic types?
Yes, although defined in the CLR.
Why do I get an InvalidCastException in the second example?
You can unbox in origin type only
What does Convert.ToInt32 in the background?
It contains a convertation
Did I label boxing, unboxing and conversion correctly? / What is the correct term when in the examples where I'm not sure?
byte a = 2;
int b = a; // convertation (byte to int)
object b = a; // boxing
int c = (int) b; //unboxing
object b = a; // boxing
int c = Convert.ToInt32(b); // convertation (object to int)
Are the conversion operators at play here? Is there an overview about the basic conversion operators of the basic types?
You can reflect framework code to learn how it works deeper.
should be
object b = a; // => boxing
int c = (int) b; //Un-boxing
I am reading a book to pass the Microsoft Exam 70-483 and I got a little stuck on the following question :
The following code is boxed into object o.
double d = 11.5;
object o = d;
You’re asked to cast object o into int. What option should you use in your code?
int i = (int)o; //Option : A
int i = (int)(double)o; //Option : B
int i = (int)(float)(double)o; //Option : C
int i = (float)o; //Option : D
According to book, true answer is C, but I could not understand why the option b is wrong. When I try to run both of them, results are the same. Is there any difference option B and option C? What are your opinions?
In your given example, option B is totally fine.
Option A: You can't box and unbox different types. This will result in an InvalidCastException.
Option B: Totally fine. o will be unboxed in a double. Afterwards it will be cast (explicit) in an integer.
Option C: Like B, but before casting it into an integer, it will be casted to an float. The Result will stay the same. There is absolutly no need for the cast from double to float. It will always truncate.
But there are edges cases! (See below)
Option D: Can't use implicit cast from float to int. Same as A: InvalidCastException
So why C?
There are cases where rounding a double to an int differs from rounding a float to an int.
See the following answer from supercat
You can reproduce this by the following example:
static void Main(string[] args)
{
double val = 12344321.4999999991;
int a = (int)(float)val;
int b = (int)val;
Console.WriteLine(a);
Console.WriteLine(b);
Console.ReadLine();
}
The output will be:
12344322
12344321
So as you can see, casting to float first, will result in a different outcome.
Keep in mind, that these are edge cases and most likely academic problems.
I realized that if I have a field or variable of type 'byte', I can apply bitwise NOT(~) on it and cast it to byte. However, if the field is 'const byte', I can still apply bitwise NOT(~), but I cannot cast it to byte. For example,
This compiles:
class Program
{
byte b = 7;
void Method()
{
byte bb = (byte) ~b;
}
}
But this has a compile error ("Constant value '-8' cannot be converted to a 'byte' "):
class Program
{
const byte b = 7;
void Method()
{
byte bb = (byte) ~b;
}
}
I wonder why?
Because the ~ operator is only predefined for int, uint, long, and ulong. Your first sample implicitly casts b to an int, performs the negation, then explicitly casts back to a byte.
In the second example, b is a constant, so the compiler is also inlining the negation, effectively making a constant int with a value of -8 (the signed twos-complement of 7). And since a constant negative value can't be cast to a byte (without adding an unchecked context), you get a compilation error.
To avoid the error just store the result in a non-constant int variable:
const byte b = 7;
void Main()
{
int i = ~b;
byte bb = (byte)i;
}
There is no ~ operator defined for byte. It's defined for int. The byte is implicitly converted to an int, and that int is NOT-ed. That resulting int is not in the range of a byte (0 - 255, inclusive), so it can only be converted to a byte at compile-time via an unchecked cast:
byte bb = unchecked((byte)~b);
The second program doesn't compile because, due to the use of compile time constants, it's able to validate the improper conversion at compile time. The compiler cannot make this assertion with non-compile time constant values.
I can't explain the difference, but the simple solution for your second program is to mark it unchecked like so:
byte bb = unchecked((byte)~b);
The below code fails at the last assignment:
static void Main(string[] args)
{
int a = 5;
object b = 5;
System.Diagnostics.Debug.Assert( a is int && b is int );
double x = (double)a;
double y = (double)b;
}
If both a and b are int, what is the cause of this error?
This is an extremely frequently asked question. See https://ericlippert.com/2009/03/03/representation-and-identity/ for an explanation.
Snippet:
I get a fair number of questions about the C# cast operator. The most frequent question I get is:
short sss = 123;
object ooo = sss; // Box the short.
int iii = (int) sss; // Perfectly legal.
int jjj = (int) (short) ooo; // Perfectly legal
int kkk = (int) ooo; // Invalid cast exception?! Why?
Why? Because a boxed T can only be unboxed to T. (*) Once it is unboxed, it’s just a value that can be cast as usual, so the double cast works just fine.
(*) Or Nullable<T>.
Unboxing requires the exact type - you can do this instead:
double y = (double)(int)b;
This is one of the rare cases where System.Convert comes in handy. You can use System.Convet.ToDouble(obj) to knock it out if you don't know before hand that it will be int.
Implicit casting is a compile-time operation. It's not possible for b of type object.
a is an int, but b is a reference to an object that is an int - it is what is called a boxed int. They are two different things, hence the different behaviors.
If compiler is able to implicitly convert integer literal into byte type and assign the result to b ( b = 100; ), why can’t it also implicitly assign the result of an expression a+100 ( result is of type integer ) to b?
byte a = 10;
byte b = a; //ok
b = 100; //ok
b = a + 100;//error - explicit cast needed
b = (byte)(a + 100); // ok
thanx
It's all about static type safety - whether, at compile time, we can safety know the type of an expression. With a literal, the compiler can correctly tell that if it can be converted to a byte. In byte a = 20, 20 is convertible, so it all goes through fine. byte a = 257 won't work (257 can't be converted).
In the case byte b = a, then we already know a is a byte, so type safety is assured. b = 100 is again fine (it's statically known that 100 is convertible).
In b = a + 100, it is not statically known if a + 100 is a byte. a could contain 200, so a + 100 is not representable as a byte. Hence the compiler forces you to tell it "Yes, a + 100 is always a byte" via a cast, by appealing to your higher level programmer knowledge.
Some types of more advanced type systems don't suffer from this problem, but come with their own problems that most programmers won't like.
The compiler allows you to implicitly convert an integer literal into a byte, since it can, at compile time, check the value of the literal to make sure that it's a byte, and treat it as a byte literal.
You can see this if you try the following:
byte a = 10; // Works, since 10 is valid as byte
byte b = 239832; // Gives error!
The error you get if you put an arbitrary int is:
Error 1 Constant value '239832' cannot be converted to a 'byte'
When you're adding a literal to a byte:
b = a + 100
There's the potential for overflowing, so it's not implicitly allowed. You need to tell the compiler that you explicitly want this to happen, via a cast.
If you use the assigning version of the operator (+=) then it will perform the narrowing conversion on the result without reporting an error:
byte a = 10;
byte b = a; //ok
b = 100; //ok
b = a;
b += 100;//ok
Because treating literals specially is easy and useful; having the compiler distinguish all expressions consisting of compile-time constants and treat them specially would be far more work and far less useful.