First, a bit of background. Read the question and accepted answer posted here for a specific scenario for my question. I'm not sure if other, similar cases exist but this is the only case I am aware of.
The above "quirk" is something that I've been aware of for a long time. I didn't understand the full breadth of the cause until just recently.
Microsoft's documentation on the SqlParameter class sheds a little more light on the situation.
When you specify an Object in the value parameter, the SqlDbType is
inferred from the Microsoft .NET Framework type of the Object.
Use caution when you use this overload of the SqlParameter constructor
to specify integer parameter values. Because this overload takes a
value of type Object, you must convert the integral value to an Object
type when the value is zero, as the following C# example demonstrates.
Parameter = new SqlParameter("#pname", Convert.ToInt32(0));
If you do
not perform this conversion, the compiler assumes that you are trying
to call the SqlParameter (string, SqlDbType) constructor overload.
(emph. added)
My question is why does the compiler assume that when you specify a hard coded "0" (and only the value "0") that you are trying to specify an enumeration type, rather than an integer type? In this case, it assumes that you are declaring SqlDbType value, instead of the value 0.
This is non-intuitive and, to make matters worse, the error is inconsistent. I have old applications that I've written which have called stored procedures for years. I'll make a change to the application (often times not even associated with my SQL Server classes), publish an update, and this issue will all of a sudden break the application.
Why is the compiler confused by the value 0, when an object containing multiple method signatures contain two, similar signatures where one parameter is an object/integer and the other accepts an enumeration?
As I've mentioned, I've never seen this as a problem with any other constructor or method on any other class. Is this unique to the SqlParameter class or is this a bug inherit within C#/.Net?
It's because a zero-integer is implicitly convertible to an enum:
enum SqlDbType
{
Zero = 0,
One = 1
}
class TestClass
{
public TestClass(string s, object o)
{ System.Console.WriteLine("{0} => TestClass(object)", s); }
public TestClass(string s, SqlDbType e)
{ System.Console.WriteLine("{0} => TestClass(Enum SqlDbType)", s); }
}
// This is perfectly valid:
SqlDbType valid = 0;
// Whilst this is not:
SqlDbType ohNoYouDont = 1;
var a1 = new TestClass("0", 0);
// 0 => TestClass(Enum SqlDbType)
var a2 = new TestClass("1", 1);
// => 1 => TestClass(object)
(Adapted from Visual C# 2008 Breaking Changes - change 12)
When the compiler performs the overload resolution 0 is an Applicable function member for both the SqlDbType and the object constructors because:
an implicit conversion (Section 6.1) exists from the type of the argument to the type of the corresponding parameter
(Both SqlDbType x = 0 and object x = 0 are valid)
The SqlDbType parameter is better than the object parameter because of the better conversion rules:
If T1 and T2 are the same type, neither conversion is better.
object and SqlDbType are not the same type
If S is T1, C1 is the better conversion.
0 is not an object
If S is T2, C2 is the better conversion.
0 is not a SqlDbType
If an implicit conversion from T1 to T2 exists, and no implicit conversion from T2 to T1 exists, C1 is the better conversion.
No implicit conversion from object to SqlDbType exists
If an implicit conversion from T2 to T1 exists, and no implicit conversion from T1 to T2 exists, C2 is the better conversion.
An implicit conversion from SqlDbType to object exists, so the SqlDbType is the better conversion
Note that what exactly constitutes a constant 0 has (quite subtly) changed in Visual C# 2008 (Microsoft's implementation of the C# spec) as #Eric explains in his answer.
RichardTowers' answer is excellent, but I thought I'd add a bit to it.
As the other answers have pointed out, the reason for the behaviour is (1) zero is convertible to any enum, and obviously to object, and (2) any enum type is more specific that object, so the method that takes an enum is therefore chosen by overload resolution as the better method. Point two is I hope self-explanatory, but what explains point one?
First off, there is an unfortunate deviation from the specification here. The specification says that any literal zero, that is, the number 0 actually literally appearing in the source code, may be implicitly converted to any enum type. The compiler actually implements that any constant zero may be thusly converted. The reason for that is because of a bug whereby the compiler would sometimes allow constant zeroes and sometimes not, in a strange and inconsistent manner. The easiest way to solve the problem was to consistently allow constant zeroes. You can read about this in detail here:
https://web.archive.org/web/20110308161103/http://blogs.msdn.com/b/ericlippert/archive/2006/03/28/the-root-of-all-evil-part-one.aspx
Second, the reason for allowing zeros to convert to any enum is to ensure that it is always possible to zero out a "flags" enum. Good programming practice is that every "flags" enum have a value "None" which is equal to zero, but that is a guideline, not a requirement. The designers of C# 1.0 thought that it looked strange that you might have to say
for (MyFlags f = (MyFlags)0; ...
to initialize a local. My personal opinion is that this decision has caused more trouble than it was worth, both in terms of the grief over the abovementioned bug and in terms of the oddities it introduces into overload resolution that you have discovered.
Finally, the designers of the constructors could have realized that this would be a problem in the first place, and made the signatures of the overloads such that the developer could clearly decide which ctor to call without having to insert casts. Unfortunately this is a pretty obscure issue and so a lot of designers are unaware of it. Hopefully anyone reading this will not make the same mistake; do not create an ambiguity between object and any enum if you intend the two overrides to have different semantics.
This is apparently a known behavior and affects any function overloads where there is both an enumeration and object type. I don't understand it all, but Eric Lippert summed it up quite nicely on his blog
This is caused by the fact that the integer literal 0 has an implicit conversion to any enum type. The C# specification states:
6.1.3 Implicit enumeration conversions
An implicit enumeration conversion permits the decimal-integer-literal
0 to be converted to any enum-type and to any nullable-type whose
underlying type is an enum-type. In the latter case the conversion is
evaluated by converting to the underlying enum-type and wrapping the
result.
As a result, the most specific overload in this case is SqlParameter(string, DbType).
This does not apply for other int values, so the SqlParameter(string, object) constructor is the most specific.
When resolving the type for an overloaded method, C# selects the most specific option. The SqlParameter class has two constructors that take exactly two arguments, SqlParameter(String, SqlDbType) and SqlParameter(String, Object). When you provide the literal 0, it can be interpreted as an Object or as a SqlDbType. Since SqlDbType is more specific than Object, it is assumed to be the intent.
You can read more about overload resolution in this answer.
Related
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?
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!
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.
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.
Conclusion: In casting you are telling to the compiler that 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'.
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
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).
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!");
}
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.
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"
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.
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.
First, a bit of background. Read the question and accepted answer posted here for a specific scenario for my question. I'm not sure if other, similar cases exist but this is the only case I am aware of.
The above "quirk" is something that I've been aware of for a long time. I didn't understand the full breadth of the cause until just recently.
Microsoft's documentation on the SqlParameter class sheds a little more light on the situation.
When you specify an Object in the value parameter, the SqlDbType is
inferred from the Microsoft .NET Framework type of the Object.
Use caution when you use this overload of the SqlParameter constructor
to specify integer parameter values. Because this overload takes a
value of type Object, you must convert the integral value to an Object
type when the value is zero, as the following C# example demonstrates.
Parameter = new SqlParameter("#pname", Convert.ToInt32(0));
If you do
not perform this conversion, the compiler assumes that you are trying
to call the SqlParameter (string, SqlDbType) constructor overload.
(emph. added)
My question is why does the compiler assume that when you specify a hard coded "0" (and only the value "0") that you are trying to specify an enumeration type, rather than an integer type? In this case, it assumes that you are declaring SqlDbType value, instead of the value 0.
This is non-intuitive and, to make matters worse, the error is inconsistent. I have old applications that I've written which have called stored procedures for years. I'll make a change to the application (often times not even associated with my SQL Server classes), publish an update, and this issue will all of a sudden break the application.
Why is the compiler confused by the value 0, when an object containing multiple method signatures contain two, similar signatures where one parameter is an object/integer and the other accepts an enumeration?
As I've mentioned, I've never seen this as a problem with any other constructor or method on any other class. Is this unique to the SqlParameter class or is this a bug inherit within C#/.Net?
It's because a zero-integer is implicitly convertible to an enum:
enum SqlDbType
{
Zero = 0,
One = 1
}
class TestClass
{
public TestClass(string s, object o)
{ System.Console.WriteLine("{0} => TestClass(object)", s); }
public TestClass(string s, SqlDbType e)
{ System.Console.WriteLine("{0} => TestClass(Enum SqlDbType)", s); }
}
// This is perfectly valid:
SqlDbType valid = 0;
// Whilst this is not:
SqlDbType ohNoYouDont = 1;
var a1 = new TestClass("0", 0);
// 0 => TestClass(Enum SqlDbType)
var a2 = new TestClass("1", 1);
// => 1 => TestClass(object)
(Adapted from Visual C# 2008 Breaking Changes - change 12)
When the compiler performs the overload resolution 0 is an Applicable function member for both the SqlDbType and the object constructors because:
an implicit conversion (Section 6.1) exists from the type of the argument to the type of the corresponding parameter
(Both SqlDbType x = 0 and object x = 0 are valid)
The SqlDbType parameter is better than the object parameter because of the better conversion rules:
If T1 and T2 are the same type, neither conversion is better.
object and SqlDbType are not the same type
If S is T1, C1 is the better conversion.
0 is not an object
If S is T2, C2 is the better conversion.
0 is not a SqlDbType
If an implicit conversion from T1 to T2 exists, and no implicit conversion from T2 to T1 exists, C1 is the better conversion.
No implicit conversion from object to SqlDbType exists
If an implicit conversion from T2 to T1 exists, and no implicit conversion from T1 to T2 exists, C2 is the better conversion.
An implicit conversion from SqlDbType to object exists, so the SqlDbType is the better conversion
Note that what exactly constitutes a constant 0 has (quite subtly) changed in Visual C# 2008 (Microsoft's implementation of the C# spec) as #Eric explains in his answer.
RichardTowers' answer is excellent, but I thought I'd add a bit to it.
As the other answers have pointed out, the reason for the behaviour is (1) zero is convertible to any enum, and obviously to object, and (2) any enum type is more specific that object, so the method that takes an enum is therefore chosen by overload resolution as the better method. Point two is I hope self-explanatory, but what explains point one?
First off, there is an unfortunate deviation from the specification here. The specification says that any literal zero, that is, the number 0 actually literally appearing in the source code, may be implicitly converted to any enum type. The compiler actually implements that any constant zero may be thusly converted. The reason for that is because of a bug whereby the compiler would sometimes allow constant zeroes and sometimes not, in a strange and inconsistent manner. The easiest way to solve the problem was to consistently allow constant zeroes. You can read about this in detail here:
https://web.archive.org/web/20110308161103/http://blogs.msdn.com/b/ericlippert/archive/2006/03/28/the-root-of-all-evil-part-one.aspx
Second, the reason for allowing zeros to convert to any enum is to ensure that it is always possible to zero out a "flags" enum. Good programming practice is that every "flags" enum have a value "None" which is equal to zero, but that is a guideline, not a requirement. The designers of C# 1.0 thought that it looked strange that you might have to say
for (MyFlags f = (MyFlags)0; ...
to initialize a local. My personal opinion is that this decision has caused more trouble than it was worth, both in terms of the grief over the abovementioned bug and in terms of the oddities it introduces into overload resolution that you have discovered.
Finally, the designers of the constructors could have realized that this would be a problem in the first place, and made the signatures of the overloads such that the developer could clearly decide which ctor to call without having to insert casts. Unfortunately this is a pretty obscure issue and so a lot of designers are unaware of it. Hopefully anyone reading this will not make the same mistake; do not create an ambiguity between object and any enum if you intend the two overrides to have different semantics.
This is apparently a known behavior and affects any function overloads where there is both an enumeration and object type. I don't understand it all, but Eric Lippert summed it up quite nicely on his blog
This is caused by the fact that the integer literal 0 has an implicit conversion to any enum type. The C# specification states:
6.1.3 Implicit enumeration conversions
An implicit enumeration conversion permits the decimal-integer-literal
0 to be converted to any enum-type and to any nullable-type whose
underlying type is an enum-type. In the latter case the conversion is
evaluated by converting to the underlying enum-type and wrapping the
result.
As a result, the most specific overload in this case is SqlParameter(string, DbType).
This does not apply for other int values, so the SqlParameter(string, object) constructor is the most specific.
When resolving the type for an overloaded method, C# selects the most specific option. The SqlParameter class has two constructors that take exactly two arguments, SqlParameter(String, SqlDbType) and SqlParameter(String, Object). When you provide the literal 0, it can be interpreted as an Object or as a SqlDbType. Since SqlDbType is more specific than Object, it is assumed to be the intent.
You can read more about overload resolution in this answer.
Normally, one would expect, and hope, that two casts are needed to first unbox a value type and then perform some kind of value type conversion into another value type. Here's an example where this holds:
// create boxed int
IFormattable box = 42; // box.GetType() == typeof(int)
// unbox and narrow
short x1 = (short)box; // fails runtime :-)
short x2 = (short)(int)box; // OK
// unbox and make unsigned
uint y1 = (uint)box; // fails runtime :-)
uint y2 = (uint)(int)box; // OK
// unbox and widen
long z1 = (long)box; // fails runtime :-)
long z2 = (long)(int)box; // OK (cast to long could be made implicit)
As you can see from my smileys, I'm happy that these conversions will fail if I use only one cast. After all, it's probably a coding mistake to try to unbox a value type into a different value type in one operation.
(There's nothing special with the IFormattable interface; you could also use the object class if you prefer.)
However, today I realized that this is different with enums (when (and only when) the enums have the same underlying type). Here's an example:
// create boxed DayOfWeek
IFormattable box = DayOfWeek.Monday; // box.GetType() == typeof(DayOfWeek)
// unbox and convert to other
// enum type in one cast
DateTimeKind dtk = (DateTimeKind)box; // succeeds runtime :-(
Console.WriteLine(box); // writes Monday
Console.WriteLine(dtk); // writes Utc
I think this behavior is unfortunate. It should really be compulsory to say (DateTimeKind)(DayOfWeek)box. Reading the C# specification, I see no justification of this difference between numeric conversions and enum conversions. It feels like the type safety is lost in this situation.
Do you think this is "unspecified behavior" that could be improved (without spec changes) in a future .NET version? It would be a breaking change.
Also, if the supplier of either of the enum types (either DayOfWeek or DateTimeKind in my example) decides to change the underlying type of one of the enum types from int to something else (could be long, short, ...), then all of a sudden the above one-cast code would stop working, which seems silly.
Of course, the enums DayOfWeek and DateTimeKind are not special. These could be any enum types, including user-defined ones.
Somewhat related: Why does unboxing enums yield odd results? (unboxes an int directly into an enum)
ADDITION:
OK, so many answers and comments have focused on how enums are treated "under the hood". While this is interesting in itself, I want to concentrate more on whether the observed behavior is covered by the C# specification.
Suppose I wrote the type:
struct YellowInteger
{
public readonly int Value;
public YellowInteger(int value)
{
Value = value;
}
// Clearly a yellow integer is completely different
// from an integer without any particular color,
// so it is important that this conversion is
// explicit
public static explicit operator int(YellowInteger yi)
{
return yi.Value;
}
}
and then said:
object box = new YellowInteger(1);
int x = (int)box;
then, does the C# spec say anything about whether this will succeed at runtime? For all I care, .NET might treat a YellowInteger as just an Int32 with different type metadata (or whatever it's called), but can anyone guarantee that .NET does not "confuse" a YellowInteger and an Int32 when unboxing? So where in the C# spec can I see if (int)box will succeed (calling my explicit operator method)?
When you use:
IFormattable box = 42;
long z2 = (long)(int)box;
You are actually unboxing and then casting.
But in your second case:
IFormattable box = DayOfWeek.Monday;
DateTimeKind dtk = (DateTimeKind)box;
You don't perform any casting at all. You just unbox the value. The default underlying type of the enumeration elements is int.
Update to refer to the real question:
The specification you mentioned in the comment:
The explicit enumeration conversions are:
...
From any enum-type to any other enum-type.
This is actually correct. We cannot implicitly convert:
//doesn't compile
DateTimeKind dtk = DayOfWeek.Monday;
But we can explicitly convert:
DateTimeKind dtk = (DateTimeKind)DayOfWeek.Monday;
It seems that you found a case when this is still required. But when combined with unboxing, only explicit conversion needs to be specified and unboxing can be ommited.
Update 2
Got a feeling that somebody must have noticed that before, went to Google, searched for "unboxing conversion enum" and guess what? Skeet blogged about it in 2005 (CLI spec mistake with unboxing and enums)
This is because they are actually represented as their underlying value type at runtime. They are both int, which follows the same situation as your failing cases - if you change the enum type in this situation, this would also fail.
As the type is the same, the action is simply unboxing the int.
You can only unbox values to their actual type, hence casting before unboxing does not work.
Update
If you create some code that casts int enumerations around with each other, you'll see that there are no casting actions in the generated IL. When you box an enum and unbox it to another type, there is just the unbox.any action which:
Converts the boxed representation of a type specified in the
instruction to its unboxed form.
In this case it is each of the enums, but they are both int.
Update 2:
I've reached my limit of being able to explain what is going on here without much more in-depth research on my part, but I spotted this question:
How is it that an enum derives from System.Enum and is an integer at the same time?
It might go a little ways to explaining how enumerations are handled.
I've seen both terms be used almost interchangeably in various online explanations, and most text books I've consulted are also not entirely clear about the distinction.
Is there perhaps a clear and simple way of explaining the difference that you guys know of?
Type conversion (also sometimes known as type cast)
To use a value of one type in a context that expects another.
Nonconverting type cast (sometimes known as type pun)
A change that does not alter the underlying bits.
Coercion
Process by which a compiler automatically converts a value of one type into a value of another type when that second type is required by the surrounding context.
Type Conversion:
The word conversion refers to either implicitly or explicitly changing a value from one data type to another, e.g. a 16-bit integer to a 32-bit integer.
The word coercion is used to denote an implicit conversion.
The word cast typically refers to an explicit type conversion (as opposed to an implicit conversion), regardless of whether this is a re-interpretation of a bit-pattern or a real conversion.
So, coercion is implicit, cast is explicit, and conversion is any of them.
Few examples (from the same source) :
Coercion (implicit):
double d;
int i;
if (d > i) d = i;
Cast (explicit):
double da = 3.3;
double db = 3.3;
double dc = 3.4;
int result = (int)da + (int)db + (int)dc; //result == 9
Usages vary, as you note.
My personal usages are:
A "cast" is the usage of a cast operator. A cast operator instructs the compiler that either (1) this expression is not known to be of the given type, but I promise you that the value will be of that type at runtime; the compiler is to treat the expression as being of the given type, and the runtime will produce an error if it is not, or (2) the expression is of a different type entirely, but there is a well-known way to associate instances of the expression's type with instances of the cast-to type. The compiler is instructed to generate code that performs the conversion. The attentive reader will note that these are opposites, which I think is a neat trick.
A "conversion" is an operation by which a value of one type is treated as a value of another type -- usually a different type, though an "identity conversion" is still a conversion, technically speaking. The conversion may be "representation changing", like int to double, or it might be "representation preserving" like string to object. Conversions may be "implicit", which do not require a cast, or "explicit", which do require a cast.
A "coercion" is a representation-changing implicit conversion.
Casting is the process by which you treat an object type as another type, Coercing is converting one object to another.
Note that in the former process there is no conversion involved, you have a type that you would like to treat as another, say for example, you have 3 different objects that inherit from a base type, and you have a method that will take that base type, at any point, if you know the specific child type, you can CAST it to what it is and use all the specific methods and properties of that object and that will not create a new instance of the object.
On the other hand, coercing implies the creation of a new object in memory of the new type and then the original type would be copied over to the new one, leaving both objects in memory (until the Garbage Collectors takes either away, or both).
As an example consider the following code:
class baseClass {}
class childClass : baseClass {}
class otherClass {}
public void doSomethingWithBase(baseClass item) {}
public void mainMethod()
{
var obj1 = new baseClass();
var obj2 = new childClass();
var obj3 = new otherClass();
doSomethingWithBase(obj1); //not a problem, obj1 is already of type baseClass
doSomethingWithBase(obj2); //not a problem, obj2 is implicitly casted to baseClass
doSomethingWithBase(obj3); //won't compile without additional code
}
obj1 is passed without any casting or coercing (conversion) because it's already of the same type baseClass
obj2 is implicitly casted to base, meaning there's no creation of a new object because obj2 can already be baseClass
obj3 needs to be converted somehow to base, you'll need to provide your own method to convert from otherClass to baseClass, which will involve creating a new object of type baseClass and filling it by copying the data from obj3.
A good example is the Convert C# class where it provides custom code to convert among different types.
According to Wikipedia,
In computer science, type conversion, type casting, type coercion, and type juggling are different ways of changing an expression from one data type to another.
The difference between type casting and type coercion is as follows:
TYPE CASTING | TYPE COERCION
|
1. Explicit i.e., done by user | 1. Implicit i.e., done by the compiler
|
2. Types: | 2. Type:
Static (done at compile time) | Widening (conversion to higher data
| type)
Dynamic (done at run time) | Narrowing (conversion to lower data
| type)
|
3. Casting never changes the | 3. Coercion can result in representation
the actual type of object | as well as type change.
nor representation. |
Note: Casting is not conversion. It is just the process by which we treat an object type as another type. Therefore, the actual type of object, as well as the representation, is not changed during casting.
I agree with #PedroC88's words:
On the other hand, coercing implies the creation of a new object in
memory of the new type and then the original type would be copied over
to the new one, leaving both objects in memory (until the Garbage
Collectors takes either away, or both).
Casting preserves the type of objects. Coercion does not.
Coercion is taking the value of a type that is NOT assignment compatible and converting to a type that is assignment compatible. Here I perform a coercion because Int32 does NOT inherit from Int64...so it's NOT assignment compatible. This is a widening coercion (no data lost). A widening coercion is a.k.a. an implicit conversion. A Coercion performs a conversion.
void Main()
{
System.Int32 a = 100;
System.Int64 b = a;
b.GetType();//The type is System.Int64.
}
Casting allows you to treat a type as if it were of a different type while also preserving the type.
void Main()
{
Derived d = new Derived();
Base bb = d;
//b.N();//INVALID. Calls to the type Derived are not possible because bb is of type Base
bb.GetType();//The type is Derived. bb is still of type Derived despite not being able to call members of Test
}
class Base
{
public void M() {}
}
class Derived: Base
{
public void N() {}
}
Source: The Common Language Infrastructure Annotated Standard by James S. Miller
Now what's odd is that Microsoft's documentation on Casting does not align with the ecma-335 specification definition of Casting.
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.
...This sounds like Coercions not Casting.
For example,
object o = 1;
int i = (int)o;//Explicit conversions require a cast operator
i.GetType();//The type has been explicitly converted to System.Int32. Object type is not preserved. This meets the definition of Coercion not casting.
Who knows? Maybe Microsoft is checking if anybody reads this stuff.
From the CLI standard:
I.8.3.2 Coercion
Sometimes it is desirable to take a value of a type that is not assignable-to a location, and convert
the value to a type that is assignable-to the type of the location. This is accomplished through
coercion of the value. Coercion takes a value of a particular type and a desired type and attempts
to create a value of the desired type that has equivalent meaning to the original value. Coercion
can result in representation change as well as type change; hence coercion does not necessarily
preserve object identity.
There are two kinds of coercion: widening, which never loses information, and narrowing, in
which information might be lost. An example of a widening coercion would be coercing a value
that is a 32-bit signed integer to a value that is a 64-bit signed integer. An example of a
narrowing coercion is the reverse: coercing a 64-bit signed integer to a 32-bit signed integer.
Programming languages often implement widening coercions as implicit conversions, whereas
narrowing coercions usually require an explicit conversion.
Some coercion is built directly into the VES operations on the built-in types (see §I.12.1). All
other coercion shall be explicitly requested. For the built-in types, the CTS provides operations
to perform widening coercions with no runtime checks and narrowing coercions with runtime
checks or truncation, according to the operation semantics.
I.8.3.3 Casting
Since a value can be of more than one type, a use of the value needs to clearly identify which of
its types is being used. Since values are read from locations that are typed, the type of the value
which is used is the type of the location from which the value was read. If a different type is to
be used, the value is cast to one of its other types. Casting is usually a compile time operation,
but if the compiler cannot statically know that the value is of the target type, a runtime cast check
is done. Unlike coercion, a cast never changes the actual type of an object nor does it change the
representation. Casting preserves the identity of objects.
For example, a runtime check might be needed when casting a value read from a location that is
typed as holding a value of a particular interface. Since an interface is an incomplete description
of the value, casting that value to be of a different interface type will usually result in a runtime
cast check.
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#.
Fails:
object o = ((1==2) ? 1 : "test");
Succeeds:
object o;
if (1 == 2)
{
o = 1;
}
else
{
o = "test";
}
The error in the first statement is:
Type of conditional expression cannot be determined because there is no implicit conversion between 'int' and 'string'.
Why does there need to be though, I'm assigning those values to a variable of type object.
Edit: The example above is trivial, yes, but there are examples where this would be quite helpful:
int? subscriptionID; // comes in as a parameter
EntityParameter p1 = new EntityParameter("SubscriptionID", DbType.Int32)
{
Value = ((subscriptionID == null) ? DBNull.Value : subscriptionID),
}
use:
object o = ((1==2) ? (object)1 : "test");
The issue is that the return type of the conditional operator cannot be un-ambiguously determined. That is to say, between int and string, there is no best choice. The compiler will always use the type of the true expression, and implicitly cast the false expression if necessary.
Edit:
In you second example:
int? subscriptionID; // comes in as a parameter
EntityParameter p1 = new EntityParameter("SubscriptionID", DbType.Int32)
{
Value = subscriptionID.HasValue ? (object)subscriptionID : DBNull.Value,
}
PS:
That is not called the 'ternary operator.' It is a ternary operator, but it is called the 'conditional operator.'
Though the other answers are correct, in the sense that they make true and relevant statements, there are some subtle points of language design here that haven't been expressed yet. Many different factors contribute to the current design of the conditional operator.
First, it is desirable for as many expressions as possible to have an unambiguous type that can be determined solely from the contents of the expression. This is desirable for several reasons. For example: it makes building an IntelliSense engine much easier. You type x.M(some-expression. and IntelliSense needs to be able to analyze some-expression, determine its type, and produce a dropdown BEFORE IntelliSense knows what method x.M refers to. IntelliSense cannot know what x.M refers to for sure if M is overloaded until it sees all the arguments, but you haven't typed in even the first argument yet.
Second, we prefer type information to flow "from inside to outside", because of precisely the scenario I just mentioned: overload resolution. Consider the following:
void M(object x) {}
void M(int x) {}
void M(string x) {}
...
M(b ? 1 : "hello");
What should this do? Should it call the object overload? Should it sometimes call the string overload and sometimes call the int overload? What if you had another overload, say M(IComparable x) -- when do you pick it?
Things get very complicated when type information "flows both ways". Saying "I'm assigning this thing to a variable of type object, therefore the compiler should know that it's OK to choose object as the type" doesn't wash; it's often the case that we don't know the type of the variable you're assigning to because that's what we're in the process of attempting to figure out. Overload resolution is exactly the process of working out the types of the parameters, which are the variables to which you are assigning the arguments, from the types of the arguments. If the types of the arguments depend on the types to which they're being assigned, then we have a circularity in our reasoning.
Type information does "flow both ways" for lambda expressions; implementing that efficiently took me the better part of a year. I've written a long series of articles describing some of the difficulties in designing and implementing a compiler that can do analysis where type information flows into complex expressions based on the context in which the expression is possibly being used; part one is here:
http://blogs.msdn.com/ericlippert/archive/2007/01/10/lambda-expressions-vs-anonymous-methods-part-one.aspx
You might say "well, OK, I see why the fact that I'm assigning to object cannot be safely used by the compiler, and I see why it's necessary for the expression to have an unambiguous type, but why isn't the type of the expression object, since both int and string are convertible to object?" This brings me to my third point:
Third, one of the subtle but consistently-applied design principles of C# is "don't produce types by magic". When given a list of expressions from which we must determine a type, the type we determine is always in the list somewhere. We never magic up a new type and choose it for you; the type you get is always one that you gave us to choose from. If you say to find the best type in a set of types, we find the best type IN that set of types. In the set {int, string}, there is no best common type, the way there is in, say, "Animal, Turtle, Mammal, Wallaby". This design decision applies to the conditional operator, to type inference unification scenarios, to inference of implicitly typed array types, and so on.
The reason for this design decision is that it makes it easier for ordinary humans to work out what the compiler is going to do in any given situation where a best type must be determined; if you know that a type that is right there, staring you in the face, is going to be chosen then it is a lot easier to work out what is going to happen.
It also avoids us having to work out a lot of complex rules about what's the best common type of a set of types when there are conflicts. Suppose you have types {Foo, Bar}, where both classes implement IBlah, and both classes inherit from Baz. Which is the best common type, IBlah, that both implement, or Baz, that both extend? We don't want to have to answer this question; we want to avoid it entirely.
Finally, I note that the C# compiler actually gets the determination of the types subtly wrong in some obscure cases. My first article about that is here:
http://blogs.msdn.com/ericlippert/archive/2006/05/24/type-inference-woes-part-one.aspx
It's arguable that in fact the compiler does it right and the spec is wrong; the implementation design is in my opinion better than the spec'd design.
Anyway, that's just a few reasons for the design of this particular aspect of the ternary operator. There are other subtleties here, for instance, how the CLR verifier determines whether a given set of branching paths are guaranteed to leave the correct type on the stack in all possible paths. Discussing that in detail would take me rather far afield.
Why is feature X this way is often a very hard question to answer. It's much easier to answer the actual behavior.
My educated guess as to why. The conditional operator is allowed to succinctly and tersely use a boolean expression to pick between 2 related values. They must be related because they are being used in a single location. If the user instead picks 2 unrelated values perhaps the had a subtle typo / bug in there code and the compiler is better off alerting them to this rather than implicitly casting to object. Which may be something they did not expect.
"int" is a primitive type, not an object while "string" is considered more of a "primitive object". When you do something like "object o = 1", you're actually boxing the "int" to an "Int32". Here's a link to an article about boxing:
http://msdn.microsoft.com/en-us/magazine/cc301569.aspx
Generally, boxing should be avoided due to performance loses that are hard to trace.
When you use a ternary expression, the compiler does not look at the assignment variable at all to determine what the final type is. To break down your original statement into what the compiler is doing:
Statement:
object o = ((1==2) ? 1 : "test");
Compiler:
What are the types of "1" and "test" in '((1==2) ? 1 : "test")'? Do they match?
Does the final type from #1 match the assignment operator type for 'object o'?
Since the compiler doesn't evaluate #2 until #1 is done, it fails.