Can anyone please tell me why does the first of the following statements throws a compilation error and the second one does not?
NewDatabase.AddInParameter(NewCommand, "#SomeString", DbType.String, SomeString ?? DBNull.Value); // <-- Throws compilation error!
NewDatabase.AddInParameter(NewCommand, "#SomeString", DbType.String, (object)(SomeString) ?? DBNull.Value); // <-- Compiles!
I tried other nullable types such as byte? and got the same result. Can anyone please tell me why do I need to cast to object first?
You need to tell the compiler what type to use. The result type of the null coalescing operator has to be the same as one of the operand types (or the underlying type of the first operand, if it's a nullable value type, in some cases). It doesn't try to find a "most specific type which both operands can be converted to" or anything like that.
For the details of how the language is defined when it comes to the null coalescing operator, see the C# 4 language specification, section 7.13:
The type of the expression a ?? b depends on which implicit conversions are available on the operands. In order of preference, the type of a ?? b is A0, A, or B, where A is the type of a (provided that a has a type), B is the type of b (provided that b has a type), and A0 is the underlying type of A if A is a nullable type, or A otherwise.
The first example fails because SomeString and DBValue.Null are not implicitly interchangable types.
That is because the type on the right-hand side of the null-coalescing operator must be implicitly convertible to the type on the left hand side (or vice versa). For your first example, the types involved are string and DBNull. These types are unrelated, so conversion fails.
DBValue.Null is not a string; it's an Object. .NET will not implicitly cast to Object in expressions; it must be explicitly told that you are expecting an Object result.
Because the expression needs to have a single return type. Since String and DbValue can't be cast to one another, the compiler can't figure out which type return do you want. When you cast to Object, you're giving the compiler a type it can cast to.
Related
This question already has an answer here:
Casting an object using the "as" keyword returns null
(1 answer)
Closed 3 years ago.
long? i = 10000;
int? s = i as int?;
Why is it giving me a null in s variable? I know that casting it using int? s = (int?)i; will work fine but why can't I use an as operator?
From MSDN:
The code is equivalent to the following expression except that the expression variable is evaluated only one time.
expression is type ? (type)expression : (type)null
Since i is int? is false the as keyword will return (int?)null.
The types aren't equivalent and you get null, that is just how as works
However, you could just direct Cast
long? i = 10000;
var s = (int?)i;
// or even better make sure its *checked*
var s = checked((int?)i);
Why does this work?
C# Language Specification 11.6.1 Nullable Conversions
...
Evaluation of a nullable conversion based on an underlying conversion
from S to T proceeds as follows:
If the nullable conversion is from S? to T?:
If the source value is null (HasValue property is false), the result is the null value of type T?.
Otherwise, the conversion is evaluated as an unwrapping from S? to S, followed by the underlying conversion from S to T, followed by a
wrapping from T to T?.
...
as does not do this, it checks the run-time types, if they are not equal returns null T?
Additional Resources
checked (C# Reference)
The checked keyword is used to explicitly enable overflow checking for
integral-type arithmetic operations and conversions.
#Update from comments
I got that we can't convert and why we can't do I but why they are
suggesting it is there any scenario where it will be useful i'e some
random image link of Compiler Error CS0077 "The as operator must be used with a reference type or nullable type ('int' is a non-nullable value type)."
The reason is (in your image example) a value type can't be null it could never work with it. The thing you are missing is there are more complex examples of what could happen, you can define implicit operators on custom types, etc.
The compiler cannot implicitly convert 'long' to 'int'
And as per MSDN
The as operator is like a cast operation. However, if the conversion
isn't possible, as returns null instead of raising an exception.
ref: as (C# Reference)
So with your code, conversion is not possible, as is returning Null.
Originally I had this impression that NULL is reference type because it is assigned to references, then encountered this concept called nullable value types, this makes my theory in an awkward situation, so is NULL value type of reference type on earth ?
The C# specification is clear on this point: the null keyword represent an expression that has no type. It is neither reference type nor value type nor pointer type. However that expression is convertible to all of those types. There is no requirement that the compiler classify all expressions as having a type, and in fact it does not.
Now you might then ask at runtime what is the type of a null reference, what is the type of a null value of nullable value type, and what is the type of a null pointer. The answers are:
a null reference does not have a type. If you have a box that can hold chocolates it is pointless to ask "what brand of chocolates are in this empty box?" A missing chocolate does not have a brand; a null reference does not have a type.
similarly, the type of a null pointer is, again, not anything; null pointer values don't point to anything. If you have a piece of paper that has the address 1600 Pennsylvania Avenue on it, you can ask "what is the colour of the house at this address", and get the answer: white. If you have a blank piece of paper, asking what the colour of the house at that address is doesn't get you any useful answer.
a null value of a nullable value type is a value of the nullable value type.
null isn't a type.
From msdn:
The null keyword is a literal that represents a null reference, one that does not refer to any object.
Nullable types are instances of the Nullable<T> struct which "Represents a value type that can be assigned null."
Neither. null is the default value for reference types, but it does not have a type itself.
Nullable value types are actually implemented as value types themselves - there are just compiler and library tricks to make them behave as expected when compared to null.
null doesn't have a type by itself in C#, as it was already said here. I think some precise examples showing the implications of this definition are missing from the other answers.
var something = null;
is invalid
string a = null; // valid. Null is implicitely casted to string.
int? b = null; // valid. Null is implicitely casted to Nullable<int>.
var c = "hello" // valid, type of c is infered by the compiler by looking at the right side of the expression.
var d = null; // not valid, compiler can't infer any type from null !
The invalid line in the above example will cause the following compilation error :
Error - CS0815 - Cannot assign to an implicitly-typed variable
and also :
Passing null to overloaded methods might require an explicit cast
void myMethod(int? myParam) { }
void myMethod(string myParam) { }
void test
{
string a = null;
myMethod(a); // no problem here, a is of type string so 2nd overload will be used.
myMethod(null); // not valid ! Compiler can't guess which one you want.
myMethod((string) null); // valid, null is casted to string so 2nd overload is to be used.
}
The invalid line in the above example will cause the following compilation error :
Error - CS0121 - The call is ambiguous between the following methods
or properties: 'myMethod(string)' and 'myMethod(int?)'
null does not reference to anything. It is just a type points to nothing. You people usually use it to de-reference an object.
The null keyword in C# does represent a null reference, so you can consider it a reference type (although technically it indicates not type).
The C# compiler and extra handling of null for use with nullable types. Nullable value types and value types and can never actually be null. When you assign or compare a Nullable value type to null the compiler will replace the code.
For example:
int? i;
if (i == null)
i = 1;
Is replaced by the compiler with:
int? i;
if (!i.HasVaue)
i = 1;
According to the documentation of the as operator, as "is used to perform certain types of conversions between compatible reference types". Since Nullable is actually a value type, I would expect as not to work with it. However, this code compiles and runs:
object o = 7;
int i = o as int? ?? -1;
Console.WriteLine(i); // output: 7
Is this correct behavior? Is the documentation for as wrong? Am I missing something?
Is this correct behavior?
Yes.
Is the documentation for as wrong?
Yes. I have informed the documentation manager. Thanks for bringing this to my attention, and apologies for the error. Obviously no one remembered to update this page when nullable types were added to the language in C# 2.0.
Am I missing something?
You might consider reading the actual C# specification rather than the MSDN documentation; it is more definitive.
I read:
Note that the as operator only performs reference conversions and boxing conversions. The as operator cannot perform other conversions, such as user-defined conversions, which should instead be performed by using cast expressions.
And boxing conversions.....
Just a guess, but I'd say it boxes o as an integer and then converts it to a nullable.
From the documentation about the as keyword:
It is equivalent to the following expression except that expression is evaluated only one time.
expression is type ? (type)expression : (type)null
The reference for is use also states it works with reference types, however, you can also do stuff like this:
int? temp = null;
if (temp is int?)
{
// Do something
}
I'm guessing it is just an inaccuracy in the reference documentation in that the type must be nullable (ie a nullable type or a reference type) instead of just a reference type.
Apparently the MSDN documentation on the as operator needs to be updated.
object o = 7;
int i = o as **int** ?? -1;
Console.WriteLine(i);
If you try the following code where we use the as operator with the value type int, you get the appropriate compiler error message that
The as operator must be used with a reference type or nullable type ('int' is a non-nullable value type)
There is an update though on the link in Community Content section that quotes:
The as operator must be used with a reference type or nullable type.
You're applying the 'as' to Object, which is a reference type. It could be null, in which case the CLR has special support for unboxing the reference 'null' to a nullable value type. This special unboxing is not supported for any other value type, so, even though Nullable is a value type, it does have certain special privledges.
This question already has answers here:
How can an object not be compared to null?
(5 answers)
C# okay with comparing value types to null
(11 answers)
Closed 9 years ago.
Int32 struct doesn't define operator overload method for == operator, so why doesn't the code cause compile time error:
if(1 == null) ... ;
Let's take a step back here. The question is confusing and the answers so far are not very clear as to what is going on here.
Shouldn't if(1 == null) cause an error?
No. That is legal, though dumb.
How does the compiler deal with operators like "=="? It does so by applying the overload resolution algorithm.
The first thing we must determine is whether this is a "user defined" equality operator or a "built in" equality operator. The left side is a built-in type. The right side has no type at all. Neither of those are user-defined types. Therefore no user-defined operator will be considered. Only built-in operators will be considered.
Once we know that, the question is "which built-in operators will be considered?" The built in operators are described in section 7.10 of the spec. They are equality operators on int, uint, long, ulong, decimal, float, double, any enum type, bool, char, object, string and any delegate type.
All of the equality operators on value types also have a "lifted" form that takes nullable value types.
We must now determine which of those operators are applicable. To be applicable, there must be an implicit conversion from both sides to the operator's type.
There is no implicit conversion from int to any enum type, bool, string or any delegate type, so those all vanish from consideration.
(There is not an implicit conversion from int to uint, ulong, etc, but since this is a literal one, there is an implicit conversion from 1 to uint, ulong, etc.)
There is no implicit conversion from null to any non-nullable value type, so those all disappear too.
What does that leave? That leaves the operators on object, int?, long?, uint?, ulong?, double?, float?, decimal? and char? the remaining nullable types.
We must now determine which one of those remaining applicable candidates is the unique "best" operator. An operator is better than another operator if its operand type is more specific. "object" is the least specific type, so it is eliminated. Clearly every nullable int can be converted to nullable long, but not every nullable long can be converted to nullable int, so nullable long is less specific than nullable int. So it is eliminated. We continue to eliminate operators in this manner. (In the case of the unsigned types we apply a special rule that says that if int? and uint? are both options then int? wins.)
I will spare you the details; ultimately that process leaves nullable int as the unique best operand type.
Therefore your program is interpreted as if((int?)1 == (int?)null), which clearly is legal, and will always be false.
Int32 struct doesn't define operator overload method for == operator
You are correct. What does that have to do with anything? The compiler is perfectly able to do the analysis without it. I don't understand the relationship you believe this fact has to your question. The fact is about a method that could be defined on a type, the question is about how overload resolution chooses a lifted built-in operator. Those two things are not related because "int" is not a user-defined type.
It is a value type rather than a reference type. So it will not need operators.
http://msdn.microsoft.com/en-us/library/s1ax56ch.aspx
The operators for primitive types (every numeric type except decimal) are defined by the language, not the runtime.
They compile to IL instructions rather than method calls (ceq for ==)
Have a look at MSDN blog. This contains an answer to your question.
This question already has answers here:
Nullable types and the ternary operator: why is `? 10 : null` forbidden? [duplicate]
(9 answers)
Conditional operator cannot cast implicitly?
(3 answers)
Closed 9 years ago.
Assume two classes, both descendants of the same superclass, like this:
class MySuperClass{}
class A : MySuperClass{}
class B : MySuperClass{}
Then this assignment won't pass the compiler:
MySuperClass p = myCondition ? new A() : new B();
The compiler complains that A and B are not compatible (Type of conditional expression cannot be determined because there is no implicit conversion between 'A' and 'B' [CS0173] ). But they are both of type MySuperClass, so in my opinion this should work. Not that it's a big deal; a simple cast is all it takes to enlighten the compiler. But surely it's a snag in the C# compiler? Don't you agree?
The results of the conditional should be of the same type. They are not.
From MSDN, (?: Operator):
Either the type of first_expression and second_expression must be the same, or an implicit conversion must exist from one type to the other.
Since A and B are not the same type and you don't seem to have defined an implicit conversion, the compiler complains.
Look to section 7.14 of the language specification
The second and third operands, x and
y, of the ?: operator control the type
of the conditional expression.
· If x has type X and y has
type Y then
o If an implicit conversion (§6.1)
exists from X to Y, but not from Y to
X, then Y is the type of the
conditional expression.
o If an implicit conversion (§6.1)
exists from Y to X, but not from X to
Y, then X is the type of the
conditional expression.
o Otherwise, no expression type can
be determined, and a compile-time
error occurs.
· If only one of x and y has a
type, and both x and y, of
areimplicitly convertible to that
type, then that is the type of the
conditional expression.
· Otherwise, no expression type can be determined, and a compile-time error occurs.
Essentially, the operands must be convertible to one another, not mutually convertible to some other type.
It's why you need to make an explicit cast in your example or in cases such as nullables (int? foo = isBar ? 42 : (int?)null). The declaration type does not impact the evaluation, the compiler must figure it out from the expression itself.
Check out this blog for some interesting articles on why C# compiler does/doesn't do things that are 'obvious' to you. The blog is written by Eric Lippert, one of the C# compiler developers.
The compiler doesn't try to look for a common ancestor, so you need an explicit cast to show which ancestor you wanted to treat it as; In your case:
MySuperClass p = myCondition ? (MySuperClass)(new A()) : (MySuperClass)(new B());
This means that the conditional operator has both sides returnin gthe same type, which satisfies the compiler.
The conditional operator (as with any other operator) has to define the type that its expression represents. In the case of the conditional operator, it has a two-step process:
Are the operands of the same type? If so, that is the type of the expression.
Is there an implicit conversion from one of the operand types to the other (but not in both directions)? If so, then the "other" is the type of the expression.
There's no ancestry search, as implementing that could lead down a slippery slope of ambiguity in what you, as a developer, could specify in that expression. Should everything lead to object? What about value types, which would then be implicitly boxed? What about interfaces? If there's more than one common interface between the two types, which one should be chosen?
In your case, as you've discovered, you need to upcast one of the operands to the parent type. Once you do that, rule 2.) is satisfied (there is always an implicit conversion going from a more specific type to a less specific type).
Note that you only need to apply the cast to one of the operands, not both.
Rowland Shaw summed it up pretty well, but to see why a common ancestor isn't used implicitly, consider what would happen if both classes were also to implement a particular interface. The compiler wouldn't be able to work out which to use for the type of the conditional operator, and so it would be forced to use object instead.