Difference Between Casting and Using the Convert.To() Method

Difference between casting and using the Convert.To() method

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.

Implicit casts

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).

Primitive types

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;

Objects

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 structs and primitive types because with a cast you create a new object of another type), what changes is your view of them.

Explicit casts

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:

  • You may lose information or data so you have to be aware of it.
  • The conversion may fail (because you can't convert one type to the other) so, again, you must be aware of what you're doing.

Primitive types

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).

Objects

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;

Conversions

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 (TypeConverters 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.

What can I do with them?

So the final question is when you should use one or another. Let's see when you can use an explicit cast:

  • Conversions between base types.
  • Conversions from object to any other type (this may include unboxing too).
  • Conversions from a derived class to a base class (or to an implemented interface).
  • Conversions from one type to another via custom conversion operators.

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:

  • Conversions from any base type to another base type (with some limitations, see MSDN).
  • Conversions from any type that implements IConvertible to any other (supported) type.
  • Conversions from/to a byte array to/from a string.

Conclusions

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.

Edit: what's the difference between them?

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!

What is the difference between casting and conversion?

I believe what Eric is trying to say is:

Casting is a term describing syntax (hence the Syntactic meaning).

Conversion is a term describing what actions are actually taken behind the scenes (and thus the Semantic meaning).

A cast-expression is used to convert
explicitly an expression to a given
type.

And

A cast-expression of the form (T)E,
where T is a type and E is a
unary-expression, performs an explicit
conversion (§13.2) of the value of E
to type T.

Seems to back that up by saying that a cast operator in the syntax performs an explicit conversion.

When to use a Cast or Convert

See Diff Between Cast and Convert on another forum

Answer

The Convert.ToInt32(String, IFormatProvider) underneath calls the Int32.Parse (read remarks).

So the only difference is that if a null string is passed it returns 0, whereas Int32.Parse throws an ArgumentNullException.

It is really a matter of choice whichever you use.

Personally, I use neither, and tend to use the TryParse functions (e.g. System.Int32.TryParse()).


UPDATE

Link on top is broken, see this answer on StackOverflow.

Difference between casting/conversion methods in C#

You are doing different things here:

  • obj.ToString() - this is a call to the ToString() method of the object. The object returns a string as it was programmed to.
  • obj as string - this is an attempt to convert the object to a string, which may or may not fail (if it fails, the result is null), no exception will be thrown.
  • (string)obj - this is an explicit cast of obj to the type string, you are telling the compiler that obj is a string. If obj is not a string type, you will get a cast exception.
  • Convert.ToString(obj) - This is an explicit call to the Convert class to return a string representation of obj.

There are these many different ways to get a string from an object because each one is different and have subtle differences. Yes, in many cases the returned string will be the same, but this is not guaranteed.

Proper time to cast vs. convert in c#

You can use cast in two cases:

  • when type you are casting to IS a type you are casting from
  • when explicit cast operator defined for these types

In all other cases you should use Convert or other custom conversion method (e.g. DateTime.Parse).

why do they return different results?

Because different code is executed. Convert.ToInt32(double value) rounds result of casting:

int num = (int) value;
double num2 = value - num;
if ((num2 > 0.5) || ((num2 == 0.5) && ((num & 1) != 0)))
num++;

return num;

Difference between Cast and Convert in C#

Casting will succeed only if the object returned by datareader["percent"] is of the type Decimal. Conversion will succeed when the object is of any type convertible to Decimal. This includes int, long, short, etc. Or more generally, anything that implements IConvertible and returns a useful value from IConvertible.ToDecimal() can be passed to Convert.ToDecimal().

For example:

csharp> object a = (int)1;

csharp> a.GetType();
System.Int32

csharp> var dec = (decimal)a;
System.InvalidCastException: Cannot cast from source type to destination type.
at Class3.Host (System.Object& $retval) [0x00000] in <filename unknown>:0
at Mono.CSharp.Evaluator.Evaluate (System.String input, System.Object& result, System.Boolean& result_set) [0x00000] in <filename unknown>:0
at Mono.CSharpShell.Evaluate (System.String input) [0x00000] in <filename unknown>:0

csharp> var dec = Convert.ToDecimal(a);

csharp> dec;
1

csharp> dec.GetType();
System.Decimal

Difference between casting with 'cast' method and 'as' keyword

as performs a cast that, after performing a runtime check, changes the static type of an object. It does not affect the identity of the object.

Collections (e.g. List, Map, Set) provide a .cast method that returns a new object (a "view") of the collection that performs as casts for each element.

void main() {
// `list1` is created as a `List<Object>` but happens to store only ints.
List<Object> list1 = <Object>[1, 2, 3];

try {
// This cast will fail because `list1` is not actually a `List<int>`.
list1 as List<int>;
} on TypeError catch (e) {
print(e); // This gets printed.
}

// `list2` is a `List`-like object that downcasts each element of `list1`
// to an `int`. `list2` is of type `List<int>`.
//
// Note that `list2` is not a copy of `list1`; mutations to `list2` will
// affect `list1`.
List<int> list2 = list1.cast<int>();

// `list3` is `list2` upcast to a `List<Object>`. If a class `Derived`
// derives from a class `Base`, then Dart also considers `List<Derived>`
// to be a derived class of `List<Base>`, so no explicit cast is necessary.
List<Object> list3 = list2;

// `list4` is `list3` downcast to `List<int>`. Since `list3` is the
// same object as `list2`, and since `list2`'s actual runtime type is
// `List<int>`, this cast succeeds (unlike `list1 as List<int>`).
List<int> list4 = list3 as List<int>;

print(identical(list1, list2)); // Prints: false
print(identical(list2, list3)); // Prints: true
print(identical(list3, list4)); // Prints: true
}

Swift: What is the difference between casting using as / as? / as! keywords and a C-style cast?

Short answer :

The C-Style cast basically means the Swift compiler will just force your closure to be called as if it takes a (Int, Float) tuple as parameter whereas the as / as? / as! cast will first do some sanity checks on your cast to ensure that the types are compatible and so on.

Since the compiler believes (in certains versions, as seen on the comments on the other answer) that (Int, Float) -> () and ((Int, Float)) -> () are too far apart to be compatible, the sanity check will just return nil, therefore blocking your call.

What makes it work is that a function / closure taking a (Int, Float) tuple behaves exactly the same (in the current version of Swift) as a function / closure taking an Int and a Float parameter.

Long answer :

I compiled a snippet of code into assembly which I will be referencing from now on. That snippet can be found here : https://swift.godbolt.org/z/CaOb0s

For readability purposes, I used functions instead of actual closures here.

I've created two functions corresponding to the two cases we have :

func twoParamFunc(a: Int, b: Float)-> Void {
print(a, b)
}

func singleParamFunc(tuple: (a: Int, b: Float))-> Void {
print(tuple.a, tuple.b)
}

I then tried to cast those using your two different methods :

    let cCastFunction = ((((Int, Float)) -> Void)?(twoParamFunc))!
let asCastFunction = (twoParamFunc as? (((Int, Float)) -> Void))!

And when looking at the assembly code compiled by swift, we can see a lot of differences between the two.

When looking at the C-style cast, we can see that most of the code is basically just calling alloc/retain/release and moving pointers and values around. The only call to external code is through a failure case (the ! dereferencing a null reference), calling $ss18_fatalErrorMessage__4file4line5flagss5NeverOs12StaticStringV_A2HSus6UInt32VtF

Whereas in the swift-style cast, there are a lot of additional calls (the sanity checks I was talking about earlier).
We have for exemple

call    (type metadata accessor for (Swift.Int, Swift.Float) -> ())
...
call (type metadata accessor for ((Swift.Int, Swift.Float)) -> ())
...
call swift_dynamicCast@PLT

which clearly shows that the Swift compiler is doing some checks to the compatibility of the types being cast, and are nowhere to be found in the c-style cast.

So now that the C-style cast / Swift-style cast difference has been found, we can try to understand why the call to the C-style casted function works.

When looking at the assembly code generated by the two simple calls to the functions I made in the sample :

    twoParamFunc(a: a.0,b: a.1)
singleParamFunc(tuple: a)

We can see that those functions are actually compiled to be called identically :

singleParamFunc :

        mov     rdi, qword ptr [rip + (output.a : (Swift.Int, Swift.Float))]
movss xmm0, dword ptr [rip + (output.a : (Swift.Int, Swift.Float))+8]
call (output.singleParamFunc(tuple: (a: Swift.Int, b: Swift.Float)) -> ())

Here we see that the value corresponding to the first value of the tuple is put into register rdi, and the second one is put into xmm0, and then the function is called

twoParamFunc :

        mov     rax, qword ptr [rip + (output.a : (Swift.Int, Swift.Float))]
movss xmm0, dword ptr [rip + (output.a : (Swift.Int, Swift.Float))+8]
...
mov rdi, rax
...
call (output.twoParamFunc(a: Swift.Int, b: Swift.Float) -> ())

In this function, it is not as straightforward, but now value 1 goes in rax register which itself is copied into rdi register, and value 2 still goes in xmm0, and the function is called.

But in this sample since we are doing other things, the assembly code is a bit messier, I've made another sample to test this cleanly : https://swift.godbolt.org/z/vDCZZV

In this sample (on which I've added another test with a struct) we can see that the assembly code created to called the 3 functions are exactly the same :

        mov     rdi, qword ptr [rip + (output.structValue : output.struct_test)]
movss xmm0, dword ptr [rip + (output.structValue : output.struct_test)+8]
call (output.test(value: output.struct_test) -> ())
        mov     rdi, qword ptr [rip + (output.tupleValue : (Swift.Int, Swift.Float))]
movss xmm0, dword ptr [rip + (output.tupleValue : (Swift.Int, Swift.Float))+8]
call (output.test2(tuple: (Swift.Int, Swift.Float)) -> ())
        mov     ecx, 1
mov edi, ecx
movss xmm0, dword ptr [rip + .LCPI0_0]
call (output.test3(a: Swift.Int, b: Swift.Float) -> ())

To resume, in the current version of swift, any of these three functions could be c-casted into any other and still work.

This ended up being a lot longer than initially planned, but I thought this problem deserved it.

Is casting the same thing as converting?

The simple answer is: it depends.

For value types, casting will involve genuinely converting it to a different type. For instance:

float f = 1.5f;
int i = (int) f; // Conversion

When the casting expression unboxes, the result (assuming it works) is usually just a copy of what was in the box, with the same type. There are exceptions, however - you can unbox from a boxed int to an enum (with an underlying type of int) and vice versa; likewise you can unbox from a boxed int to a Nullable<int>.

When the casting expression is from one reference type to another and no user-defined conversion is involved, there's no conversion as far as the object itself is concerned - only the type of the reference "changes" - and that's really only the way that the value is regarded, rather than the reference itself (which will be the same bits as before). For example:

object o = "hello";
string x = (string) o; // No data is "converted"; x and o refer to the same object

When user-defined conversions get involved, this usually entails returning a different object/value. For example, you could define a conversion to string for your own type - and
this would certainly not be the same data as your own object. (It might be an existing string referred to from your object already, of course.) In my experience user-defined conversions usually exist between value types rather than reference types, so this is rarely an issue.

All of these count as conversions in terms of the specification - but they don't all count as converting an object into an object of a different type. I suspect this is a case of Jesse Liberty being loose with terminology - I've noticed that in Programming C# 3.0, which I've just been reading.

Does that cover everything?



Related Topics



Leave a reply



Submit