Below is a posting from the following article:
The difference between coercion and casting is often neglected. I can see why; many languages have the same (or similar) syntax and terminology for both operations. Some languages may even refer to any conversion as “casting,” but the following explanation refers to concepts in the CTS.
If you are trying to assign a value of some type to a location of a different type, you can generate a value of the new type that has a similar meaning to the original. This is coercion. Coercion lets you use the new type by creating a new value that in some way resembles the original. Some coercions may discard data (e.g. converting the int 0x12345678 to the short 0x5678), while others may not (e.g. converting the int 0x00000008 to the short 0x0008, or the long 0x0000000000000008).
Recall that values can have multiple types. If your situation is slightly different, and you only want to select a different one of the value’s types, casting is the tool for the job. Casting simply indicates that you wish to operate on a particular type that a value includes.
The difference at the code level varies from C# to IL. In C#, both casting and coercion look fairly similar:
static void ChangeTypes(int number, System.IO.Stream stream)
{
long longNumber = number;
short shortNumber = (short)number;
IDisposable disposableStream = stream;
System.IO.FileStream fileStream = (System.IO.FileStream)stream;
}
At the IL level they are quite different:
ldarg.0
conv.i8
stloc.0
ldarg.0
conv.i2
stloc.1
ldarg.1
stloc.2
ldarg.1
castclass [mscorlib]System.IO.FileStream
stloc.3
As for the logical level, there are some important differences. What’s most important to remember is that coercion creates a new value, while casting does not. The identity of the original value and the value after casting are the same, while the identity of a coerced value differs from the original value; coersion creates a new, distinct instance, while casting does not. A corollary is that the result of casting and the original will always be equivalent (both in identity and equality), but a coerced value may or may not be equal to the original, and never shares the original identity.
It’s easy to see the implications of coercion in the examples above, as the numeric types are always copied by value. Things get a bit trickier when you’re working with reference types.
class Name : Tuple<string, string>
{
public Name(string first, string last)
: base(first, last)
{
}
public static implicit operator string[](Name name)
{
return new string[] { name.Item1, name.Item2 };
}
}
In the example below, one conversion is a cast, while the other is a coercion.
Tuple<string, string> tuple = name;
string[] strings = name;
After these conversions, tuple and name are equal, but strings is not equal to either of them. You could make the situation slightly better (or slightly more confusing) by implementing Equals() and operator ==() on the Name class to compare a Name and a string[]. These operators would “fix” the comparison issue, but you would still have two separate instances; any modification to strings would not be reflected in name or tuple, while changes to either one of name or tuple would be reflected in name and tuple, but not in strings.
Although the example above was meant to illustrate some differences between casting and coercion, it also serves as a great example of why you should be extremely cautious about using conversion operators with reference types in C#.