I thought T?
is just a compiler shorthand for Nullable<T>
. According to MSDN:
The syntax
T?
is shorthand forNullable<T>
, whereT
is a value type. The two forms are interchangeable.
However, there is a little (insignificant) difference: Visual Studio doesn't allow me to call static methods on shorthands:
bool b1 = Nullable<int>.Equals(1, 2); //no error
bool b2 = int?.Equals(1, 2); //syntax error "Invalid expression term 'int'"
Why? Is there any reason for this limitation?
Very well you can call a static method with null object.
Within a static method, you do not have an instance of the class. So it will be impossible to call an instance method on an instance when no instance exists.
Static methods can access the static variables and static methods directly. Static methods can't access instance methods and instance variables directly. They must use reference to object. And static method can't use this keyword as there is no instance for 'this' to refer to.
Yes. The compiler optimizes the code to invoke the static method using null object reference since object instance is not required to invoke a static method. In case of calling a non-static (instance) method using null object reference, it will throw NullPointerException.
Your MSDN quote echoes §4.1.10 of the C# 5.0 specification:
A nullable type is written
T?
, whereT
is the underlying type. This syntax is shorthand forSystem.Nullable<T>
, and the two forms can be used interchangeably.
But “interchangeably” is an oversimplification. It’s true that T?
means System.Nullable<T>
, but as you’ve discovered, you can’t use T?
everywhere that you can use System.Nullable<T>
. In particular, the kind of member-access (§7.6.4) in your example requires a simple-name (§7.6.2):
[§7.6] Primary expressions include the simplest forms of expressions.
primary-expression:
primary-no-array-creation-expression
array-creation-expressionprimary-no-array-creation-expression
literal
simple-name
parenthesized-expression
member-access
...[§7.6.2] A simple-name is either of the form
I
or of the formI<A1, ..., AK>
, whereI
is a single identifier and<A1, ..., AK>
is an optional type-argument-list.[§7.6.4] A member-access is either of the form
E.I
or of the formE.I<A1, ..., AK>
, whereE
is a primary-expression,I
is a single identifier and<A1, ..., AK>
is an optional type-argument-list.
Nullable<T>
is a simple-name and T?
isn’t, so the former compiles whereas the latter doesn’t.
Why did the C# language designers require a member-access expression to use a simple-name as opposed to any type? I suppose only they can say for sure, but maybe this requirement simplified the grammar: In an expression, the compiler can assume that ?
is always the conditional (ternary) operator instead of possibly a nullable type specifier.
In hindsight though, this was a fortunate choice that allowed C# 6.0 to add the ?.
operator without possibly breaking existing programs. For example, consider this pathological example:
struct S
{
public bool Equals(int x, int y) { return false; }
}
class C
{
public static void Main()
{
S? S = new S();
Console.WriteLine(S?.Equals(1, 1)); // "True" or "False"?
}
}
Should S?.Equals
be parsed as Nullable<S> . Equals
, a call to the Equals
static method of class Object
? Or should it be parsed as S ?. Equals
, a null-conditional call to the Equals
instance method of variable S
? Because S?
isn’t a simple-name, it’s unambiguously the latter.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With