Reputation:
I have a function that casts a double
on string
values.
string variable = "5.00";
double varDouble = (double)variable;
A code change was checked in and the project builds with the error: System.InvalidCastException: Specified cast is not valid.
However, after doing the following...
string variable = "5.00";
double varDouble = Convert.ToDouble(variable);
...the project builds without any errors.
What is the difference between casting and using the Convert.To()
method? Why does casting throw an Exception
and using the Convert.To()
does not?
Upvotes: 130
Views: 64970
Reputation: 67080
Even if you may see them somehow as equivalent they're completely different in purpose. Let's first try to define what a cast is:
Casting is the action of changing an entity of one data type into another.
It's a little bit generic and it's somehow equivalent to a conversion because a cast often has the same syntax of a conversion so the question should be when a cast (implicit or explicit) is allowed by the language and when do you have to use a (more) explicit conversion?
Let me first draw a simple line between them. Formally (even if equivalent for language syntax) a cast will change the type while a conversion will/may change the value (eventually together with the type). Also a cast is reversible while a conversion may not be.
This topic is pretty vast so let's try to narrow it a little bit by excluding custom cast operators from the game.
In C# a cast is implicit when you won't lose any information (please note that this check is performed with types and not with their actual values).
For example:
int tinyInteger = 10;
long bigInteger = tinyInteger;
float tinyReal = 10.0f;
double bigReal = tinyReal;
These casts are implicit because during the conversion you won't lose any information (you just make the type wider). Vice versa implicit cast isn't allowed because, regardless of their actual values (because they can be checked only at run-time), during the conversion you may lose some information. For example this code won't compile because a double
may contain (and actually it does) a value not representable with a float
:
// won't compile!
double bigReal = Double.MaxValue;
float tinyReal = bigReal;
In case of an object (a pointer to) the cast is always implicit when the compiler can be sure that the source type is a derived class (or it implements) the type of the target class, for example:
string text = "123";
IFormattable formattable = text;
NotSupportedException derivedException = new NotSupportedException();
Exception baseException = derivedException;
In this case the compiler knows that string
implements IFormattable
and that NotSupportedException
is (derives from) Exception
so the cast is implicit. No information is lost because objects don't change their types (this is different with struct
s and primitive types because with a cast you create a new object of another type), what changes is your view of them.
A cast is explicit when the conversion isn't done implicitly by the compiler and then you must use the cast operator. Usually it means that:
An explicit cast is required for primitive types when during the conversion you may lose some data, for example:
double precise = Math.Cos(Math.PI * 1.23456) / Math.Sin(1.23456);
float coarse = (float)precise;
float epsilon = (float)Double.Epsilon;
In both examples, even if the values fall within the float
range, you'll lose information (in this case precision) so the conversion must be explicit. Now try this:
float max = (float)Double.MaxValue;
This conversion will fail so, again, it must be explicit so you're aware of it and you may do a check (in the example the value is constant but it may come from some run-time computations or I/O). Back to your example:
// won't compile!
string text = "123";
double value = (double)text;
This won't compile because the compiler can't convert text to numbers. Text may contain any characters, not numbers only and this is too much, in C#, even for an explicit cast (but it may be allowed in another language).
Conversions from pointers (to objects) may fail if the types are unrelated, for example this code won't compile (because the compiler knows there is no possible conversion):
// won't compile!
string text = (string)AppDomain.Current;
Exception exception = (Exception)"abc";
This code will compile but it may fail at run-time (it depends on the effective type of casted objects) with an InvalidCastException
:
object obj = GetNextObjectFromInput();
string text = (string)obj;
obj = GetNextObjectFromInput();
Exception exception = (Exception)obj;
So, finally, if casts are conversions then why do we need classes like Convert
? Ignoring the subtle differences that come from Convert
implementation and IConvertible
implementations actually because in C# with a cast you say to the compiler:
trust me, this type is that type even if you can't know it now, let me do it and you'll see.
-or-
don't worry, I don't care if something will be lost in this conversion.
For anything else a more explicit operation is needed (think about implications of easy casts, that's why C++ introduced long, verbose and explicit syntax for them). This may involve a complex operation (for string
-> double
conversion a parsing will be needed). A conversion to string
, for example, is always possible (via ToString()
method) but it may mean something different from what you expect so it must be more explicit than a cast (more you write, more you think about what you're doing).
This conversion can be done inside the object (using known IL instructions for that), using custom conversion operators (defined in the class to cast) or more complex mechanisms (TypeConverter
s or class methods, for example). You're not aware of what will happen to do that but you're aware it may fail (that's why IMO when a more controlled conversion is possible you should use it). In your case the conversion simply will parse the string
to produce a double
:
double value = Double.Parse(aStringVariable);
Of course this may fail so if you do it you should always catch the exception it may throw (FormatException
). It's out of topic here but when a TryParse
is available then you should use it (because semantically you say it may not be a number and it's even faster...to fail).
Conversions in .NET can come from a lot of places, TypeConverter
, implicit/explicit casts with user defined conversion operators, implementation of IConvertible
and parsing methods (did I forget something?). Take a look on MSDN for more details about them.
To finish this long answer just few words about user defined conversion operators. It's just sugar to let the programmer use a cast to convert one type to another. It's a method inside a class (the one that will be casted) that says "hey, if he/she wants to convert this type to that type then I can do it". For example:
float? maybe = 10; // Equals to Nullable<float> maybe = 10;
float sure1 = (float)maybe; // With cast
float sure2 = maybe.Value; // Without cast
In this case it's explicit because it may fail but this is let to the implementation (even if there are guidelines about this). Imagine you write a custom string class like this:
EasyString text = "123"; // Implicit from string
double value = (string)text; // Explicit to double
In your implementation you may decide to "make programmer's life easier" and to expose this conversion via a cast (remember it's just a shortcut to write less). Some language may even allow this:
double value = "123";
Allowing implicit conversion to any type (check will be done at run-time). With proper options this can be done, for example, in VB.NET. It's just a different philosophy.
So the final question is when you should use one or another. Let's see when you can use an explicit cast:
object
to any other type (this may include unboxing too).Only the first conversion can be done with Convert
so for the others you have no choice and you need to use an explicit cast.
Let's see now when you can use Convert
:
IConvertible
to any other (supported) type.byte
array to/from a string.IMO Convert
should be used each time you know a conversion may fail (because of the format, because of the range or because it may be unsupported), even if the same conversion can be done with a cast (unless something else is available). It makes clear to who will read your code what's your intent and that it may fail (simplifying debug).
For everything else you need to use a cast, no choice, but if another better method is available then I suggest you use it. In your example a conversion from string
to double
is something that (especially if text comes from user) very often will fail so you should make it as much explicit as possible (moreover you get more control over it), for example using a TryParse
method.
According to updated question and keeping what I wrote before (about when you can use a cast compared to when you can/have to use Convert
) then last point to clarify is if there are difference between them (moreover Convert
uses IConvertible
and IFormattable
interfaces so it can perform operations not allowed with casts).
Short answer is yes, they behave differently. I see the Convert
class like a helper methods class so often it provides some benefit or slightly different behaviors. For example:
double real = 1.6;
int castedInteger = (int)real; // 1
int convertedInteger = Convert.ToInt32(real); // 2
Pretty different, right? The cast truncates (it's what we all expect) but Convert
performs a rounding to nearest integer (and this may not be expected if you're not aware of it). Each conversion method introduces differences so a general rule can't be applied and they must be seen case by case...19 base types to convert to every other type...list can be pretty long, much better to consult MSDN case by case!
Upvotes: 170
Reputation: 117
The most important difference is that if type casting is used and the conversion fails (say we are converting a very big float value to int ) no exception will be thrown and the minimum value an int can hold will be shown. But in case of using Convert , an exception will be thrown for such scenarios.
Upvotes: -1
Reputation: 39946
From MSDN
:
Explicit conversions (casts): Explicit conversions require a cast operator. Casting is required when information might be lost in the conversion, or when the conversion might not succeed for other reasons. Typical examples include numeric conversion to a type that has less precision or a smaller range, and conversion of a base-class instance to a derived class.
Consider the following example:
double a = 2548.3;
int b;
b = (int)a; //2548 --> information (.3) lost in the conversion
And also:
A cast is a way of explicitly informing the compiler that you intend to make the conversion and that you are aware that data loss might occur.
You could use System.Convert
class when you want to convert between non-compatible types. The main difference between casting and convert is compile and run-time. The type conversion exceptions are appeared at run-time , i.e a type cast that fails at run-time will cause an InvalidCastException
to be thrown.
a
is really type b
and if so the project builds without any errors like this example:
double s = 2;
int a = (int) s;
But in conversion you're saying to the compiler there is a way to create a new object from a
of type b
, please do it and project builds without any errors but as I said if type cast fails at run-time, it will cause an InvalidCastException
to be thrown.
For example the code below is never compile because compiler detect that cannot cast expression of type DateTime
to type int
:
DateTime s = DateTime.Now;
int a = (int)(s);
But this one is compiled successfully:
DateTime s = DateTime.Now;
int a = Convert.ToInt32(s);
But at run-time you will get InvalidCastException
which says:
Invalid cast from 'DateTime' to 'Int32'.
Upvotes: 6
Reputation: 29207
double varDouble = (double)variable
assumes that variable
is already a double. If variable
isn't a double (it's a string) then this will fail.
double varDouble = Convert.ToDouble(variable)
does like it says - it converts. If it can parse or otherwise extract a double from variable
then it will.
I second using Double.Parse
or Double.TryParse
because it more clearly indicates what's supposed to be happening. You're starting with a string and expecting it to be convertible to a double. If there's any doubt, use TryParse
.
If variable
is a method argument, change the type to double. Make the caller responsible for providing the correct type. That way the compiler does the work for you.
Upvotes: 2
Reputation: 112259
Casting does not involve any conversion, i.e. the internal representation of a value is not changed. Example:
object o = "Hello"; // o is typed as object and contains a string.
string s = (string)o; // This works only if o really contains a string or null.
You can convert a double
to string
like this
double d = 5;
string s = d.ToString(); // -> "5"
// Or by specifying a format
string formatted = d.ToString("N2"); // -> "5.00"
You can convert a string
to a double
in several ways (here just two of them):
string s = "5";
double d = Double.Parse(s); // Throws an exception if s does not contain a valid number
Or the safe way
string s = "5";
double d;
if (Double.TryParse(s, out d)) {
Console.WriteLine("OK. Result = {0}", d);
} else {
Console.WriteLine("oops!");
}
Upvotes: 4
Reputation:
Casting a string to a double like that is not allowed C# which is why you get an Exception, you need to have the string converted (MSDN doc that shows acceptable conversion paths). This is simply because a string isn't necessarily going to contain numeric data, but the various numeric types will (barring null values). A Convert
will run a method that will check the string to see if it can be turned into a numeric value. If it can, then it will return that value. If it can't, it'll throw an exception.
To convert it, you have several options. You used the Convert
method in your question, there's Parse
which is largely similar to Convert
, but you should also look at TryParse which would allow you to do:
string variable = "5.00";
double varDouble;
if (Double.TryParse(variable, out varDouble)) {
//Code that runs if the conversion succeeded.
} else {
//Code that runs if the conversion failed.
}
This avoids the possible exception should you try to Convert
or Parse
a non-numerical string.
Upvotes: 1
Reputation: 12815
string variable = "5.00";
double varDouble = (double)variable;
Above conversion is simply not allowed by language. Here is a list of explicit casts for numerical types: http://msdn.microsoft.com/en-us/library/yht2cx7b.aspx As you can see, even not every numerical type could be converted to another numerical type
Some more info about casting here
And how does this differ to Convert.ToDouble()?
When you cast a type, data structure is not changed. Well, in case of numerical values conversion it you may loose few bits or get few additional 0 bits. But you are still working with a number. You are just changing an amount of memory taken by that number. That is safe enough for compiler do everything needed.
But when you are trying to cast string to a number, you can't do that because it is not enough to change amount of memory taken by variable. For instance, 5.00 as a string is a sequence of "numbers":53(5) 46(.) 48(0) 48(0) - that is for ASCII, but string will contain something similar. If compiler will just take first N (4 for double? not sure) bytes from a string - that piece will contain completely different double number. At the same time Convert.ToDouble() run special algorithm which will take each symbol of a string, figure out digit which it represents and make a double number for you, if string represents a number. Languages like PHP will, roughly speaking, call Convert.ToDouble for you in background. But C#, like a statically typed language, will not do that for you. This allows you to be sure that any operation is type safe and you will not get something unexpected doing something like:
double d = (double)"zzzz"
Upvotes: 1
Reputation: 203802
Casting is a way of telling the compiler, "I know that you think that this variable is a Bar, but I happen to know more than you; the object is actually a Foo, so let me treat it as if it were a Foo from now on." Then, at runtime, if the actual object turned out to really be a Foo then your code works, if it turns out that the object was not a Foo at all, then you get an exception. (Specifically an System.InvalidCastException
.)
Converting on the other hand is a way of saying, "If you give me an object of type Bar I can create a brand new Foo object that represents what is in that Bar object. I won't change the original object, it won't treat the original object differently, it will create something new that is just based on some other value. As to how it will do that, it could be anything. In the case of Convert.ToDouble
it will end up calling Double.Parse
which has all sorts of complex logic for determining what types of strings represent what numeric values. You could write your own conversion method that mapped strings to doubles differently (perhaps to support some entirely different convention for displaying numbers, such as roman numerals or whatever). A conversion could do anything, but the idea is that you're not really asking the compiler to do anything for you; you are the one writing the code to determine how to create the new object because the compiler, without your help, has no way of knowing how to map (as an example) a string
to a double
.
So, when do you convert, and when do you cast? In both cases we have some variable of a type, let's say A, and we want to have a variable of type B. If our A object really, actually, under the hood, is a B, then we cast. If it's not really a B, then we need to Convert it, and define how the program is supposed to get a B from an A.
Upvotes: 14
Reputation: 9837
The Convert.Double
method actually just internally calls the Double.Parse(string)
method.
Neither the String
type nor the Double
type define an explicit/implicit conversion between the two types, so casting will always fail.
The Double.Parse
method will look at each character in the string
and build a numeric value based on the values of the characters in the string
. If any of the characters are invalid, the Parse
method fails (causing the Convert.Double
method to fail as well).
Upvotes: 4
Reputation: 17680
In your example you are attempting to cast a string to a double (non integral type).
An explicit conversion is required for it to work.
And i must point that you could have used Convert.ToDouble
instead of Convert.ToInt64
as you can lose the fractional parts of the double value when you convert to an int.
if your variable has the value "5.25" varDouble would have been 5.00 (loss of 0.25 because of the Conversion to Int64)
To answer your question about casting vs converting.
Your cast (an explicit cast) doesn't meet the requirements for an explicit cast. the value you are trying to cast with the cast operator is invalid (i.e non integral).
Visit this MSDN Page for the rules of casting / conversions
Upvotes: 4