Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does pattern matching on a nullable result in syntax errors?

I like to use pattern-matching on a nullable int i.e. int?:

int t  = 42;
object tobj = t;    
if (tobj is int? i)
{
    System.Console.WriteLine($"It is a nullable int of value {i}");
}

However, this results in the following syntax errors:

  • CS1003: Syntax error, ';',
  • CS1525: Invalid expression term ')',
  • CS0103: The name 'i' does not exist in the current context.

'i)' is marked with a red squiggly line.

The expression compiles when using the old operator is:

int t = 42;
object tobj = t;    
if (tobj is int?)
{
    System.Console.WriteLine($"It is a nullable int");
}


string t = "fourty two";
object tobj = t;
if (tobj is string s)
{
    System.Console.WriteLine($@"It is a string of value ""{s}"".");
}

Also works as expected.

(I'm using c#-7.2 and tested with both .net-4.7.1 and .net-4.6.1)

I thought it had something to with operator precedence. Therefore, I have tried using parenthesis at several places but this didn't help.

Why does it give these syntax errors and how can I avoid them?

like image 727
Kasper van den Berg Avatar asked Jan 19 '18 14:01

Kasper van den Berg


People also ask

How does pattern matching work?

Pattern Matching works by "reading" through text strings to match patterns that are defined using Pattern Matching Expressions, also known as Regular Expressions. Pattern Matching can be used in Identification as well as in Pre-Classification Processing, Page Processing, or Storage Processing.

What is the purpose of a nullable type?

You typically use a nullable value type when you need to represent the undefined value of an underlying value type. For example, a Boolean, or bool , variable can only be either true or false .

Does C# have pattern matching?

C# pattern matching provides more concise syntax for testing expressions and taking action when an expression matches. The " is expression" supports pattern matching to test an expression and conditionally declare a new variable to the result of that expression.

Why do we use Nullable in C#?

The Nullable type allows you to assign a null value to a variable. Nullable types introduced in C#2.0 can only work with Value Type, not with Reference Type. The nullable types for Reference Type is introduced later in C# 8.0 in 2019 so that we can explicitly define if a reference type can or can not hold a null value.


2 Answers

The type pattern in its various forms: x is T y, case T y etc, always fails to match when x is null. This is because null doesn't have a type, so asking "is this null of this type?" is a meaningless question.

Therefore t is int? i or t is Nullable<int> i makes no sense as a pattern: either t is an int, in which case t is int i will match anyway, or it's null, in which case no type pattern can result in a match.

And that is the reason why t is int? i or t is Nullable<int> i are not, and probably never will be, supported by the compiler.

The reason why you get additional errors from the compiler when using t is int? i is due to the fact that, e.g. t is int? "it's an int" : "no int here" is valid syntax, thus the compiler gets confused over your attempts to use ? for a nullable type in this context.

As to how can you avoid them, the obvious (though probably not very helpful) answer is: don't use nullable types as the type in type patterns. A more useful answer would require you to explain why you are trying to do this.

like image 163
David Arno Avatar answered Oct 24 '22 15:10

David Arno


Change your code into:

int t = 42;
object tobj = t;
if (tobj is Nullable<int> i)
{
    Console.WriteLine($"It is a nullable int of value {i}");
}

This produces the more helpful:

  • CS8116: It is not legal to use nullable type 'int?' in a pattern; use the underlying type 'int' instead (Could not find documentation about CS8116 to reference)

Others (user @Blue0500 at github ) have tagged this behaviour as a bug Roslyn issue #20156. Reacting to Roslyn issue #20156, Julien Couvreur from Microsoft has said he thinks it is by design.
Neal Gafter from Microsoft working on Roslyn has also said better diagnostics are wanted for use of nullable type is switch pattern.

So, the error message can be avoided by using:

int t = 42;
object tobj = t;
if (tobj == null)
{
    Console.WriteLine($"It is null");
}
else if (tobj is int i)
{
    Console.WriteLine($"It is a int of value {i}");
}

Except for issues when parsing tobj is int? i, this still leaves the question why is tobj is int? i or tobj is Nullable<int> i not allowed.

like image 6
Kasper van den Berg Avatar answered Oct 24 '22 15:10

Kasper van den Berg