404 Not Found

404 Not Found


nginx

Nullable Types and Pattern Matching

Nullable Value Types

Value types cannot be null by default. The Nullable<T> struct (shorthand T?) allows value types to carry null semantics.

CSHARP
int? a = 42;
int? b = null;
bool? flag = null;
double? price = 9.99;

Console.WriteLine(a.HasValue);
Console.WriteLine(b.HasValue);
Console.WriteLine(flag.GetValueOrDefault());
Console.WriteLine(price.GetValueOrDefault(0.0));
TEXT
True
False
False
9.99

Example

CSHARP
int? score = null;

Console.WriteLine(score.HasValue);
Console.WriteLine(score.GetValueOrDefault());
Console.WriteLine(score.GetValueOrDefault(60));

score = 88;
Console.WriteLine(score.Value);
▶ Try it Yourself
TEXT
False
0
60
88

Null Coalescing and Null Conditional Operators

?? provides a default value, ?. safely accesses members, and ! tells the compiler "this is not null here."

CSHARP
int? x = null;
int y = x ?? 0;

string? name = null;
int? len = name?.Length;

string s = null!;
Console.WriteLine(s is null);
TEXT
True

Example

CSHARP
string? input = null;

string display = input ?? "(empty)";
Console.WriteLine(display);

int? length = input?.Length;
Console.WriteLine(length ?? -1);

string? city = "Beijing";
Console.WriteLine(city?.Length ?? 0);
▶ Try it Yourself
TEXT
(empty)
-1
7

Nullable Reference Types

Starting with C# 8, you can use #nullable enable to turn on nullable reference type warnings. string? allows null, string does not.

CSHARP
#nullable enable
string? maybeNull = null;
string notNull = "hello";

maybeNull = null;
notNull = null!;

Example

CSHARP
#nullable enable
string Greet(string? name)
{
    return name is null ? "Hello, stranger" : $"Hello, {name}";
}

Console.WriteLine(Greet(null));
Console.WriteLine(Greet("Alice"));
▶ Try it Yourself
TEXT
Hello, stranger
Hello, Alice

Null Check Strategies

Strategy Usage Scenario
Explicit check if (x is null) Branch logic needed
Null coalescing x ?? defaultValue Providing a default value
Null conditional x?.Member Safe member access

Example

CSHARP
string? GetName() => null;

string? name = GetName();

if (name is null)
{
    Console.WriteLine("Name is null");
}

string upper = name?.ToUpper() ?? "DEFAULT";
Console.WriteLine(upper);
▶ Try it Yourself
TEXT
Name is null
DEFAULT

Introduction to Pattern Matching

Pattern matching combines type checking and variable extraction into one, commonly used with is and switch.

is Pattern

CSHARP
object obj = 42;

if (obj is int i)
{
    Console.WriteLine($"Is integer: {i}");
}
TEXT
Is integer: 42

Example

CSHARP
object value = "hello";

if (value is int n)
{
    Console.WriteLine(n);
}
else if (value is string s)
{
    Console.WriteLine($"String length: {s.Length}");
}
▶ Try it Yourself
TEXT
String length: 5

Type Pattern and switch

Branch by type in switch and extract variables.

Example

CSHARP
string Describe(object obj)
{
    return obj switch
    {
        int i => $"Integer {i}",
        double d => $"Double {d}",
        string s => $"String \"{s}\"",
        bool b => $"Boolean {b}",
        null => "null",
        _ => "Unknown type"
    };
}

Console.WriteLine(Describe(10));
Console.WriteLine(Describe(3.14));
Console.WriteLine(Describe("hi"));
Console.WriteLine(Describe(true));
▶ Try it Yourself
TEXT
Integer 10
Double 3.14
String "hi"
Boolean True

Property Pattern

Property patterns match by object properties without manually extracting values for comparison.

Example

CSHARP
var person = new { Name = "Alice", Age = 20 };

if (person is { Age: > 18 })
{
    Console.WriteLine("Adult");
}

string Category(object p) => p switch
{
    { Age: < 12 } => "Child",
    { Age: >= 12 and < 18 } => "Teenager",
    { Age: >= 18 } => "Adult",
    _ => "Unknown"
};

Console.WriteLine(Category(person));
▶ Try it Yourself
TEXT
Adult
Adult

Record Type

C# 9 introduced record, which provides value-based equality comparison and immutability by default.

CSHARP
record Person(string Name, int Age);

Example

CSHARP
record Person(string Name, int Age);

var p1 = new Person("Alice", 18);
var p2 = new Person("Alice", 18);

Console.WriteLine(p1 == p2);
Console.WriteLine(ReferenceEquals(p1, p2));
Console.WriteLine(p1);
▶ Try it Yourself
TEXT
True
False
Person { Name = Alice, Age = 18 }

with Expression

with creates a copy of an existing record with some properties modified, leaving the original instance unchanged.

Example

CSHARP
record Student(string Name, int Age, string Grade);

var s1 = new Student("Bob", 20, "A");
var s2 = s1 with { Age = 21, Grade = "A+" };

Console.WriteLine(s1);
Console.WriteLine(s2);
▶ Try it Yourself
TEXT
Student { Name = Bob, Age = 20, Grade = A }
Student { Name = Bob, Age = 21, Grade = A+ }

Tuple

Tuples combine multiple values into a lightweight structure, supporting named elements and deconstruction.

Example

CSHARP
(int Id, string Name) person = (1, "Charlie");
Console.WriteLine(person.Id);
Console.WriteLine(person.Name);

var coords = (X: 3.0, Y: 4.0);
double distance = Math.Sqrt(coords.X * coords.X + coords.Y * coords.Y);
Console.WriteLine(distance);

(int x, int y) = (10, 20);
Console.WriteLine($"x={x}, y={y}");
▶ Try it Yourself
TEXT
1
Charlie
5
x=10, y=20

Tuple Deconstruction and Pattern Matching

Combining tuples with pattern matching elegantly handles multi-condition branches.

Example

CSHARP
string Classify(int score, bool hasBonus) => (score, hasBonus) switch
{
    (>= 90, true) => "Excellent+Bonus",
    (>= 90, false) => "Excellent",
    (>= 60, true) => "Pass+Bonus",
    (>= 60, false) => "Pass",
    _ => "Fail"
};

Console.WriteLine(Classify(95, true));
Console.WriteLine(Classify(75, false));
Console.WriteLine(Classify(50, true));
▶ Try it Yourself
TEXT
Excellent+Bonus
Pass
Fail

❓ FAQ

Q Can int? and int be used in arithmetic directly?
A No. You need to convert to a non-null value using .Value or ?? before operating.
Q What is the difference between string? and string?
A string? allows assigning null, while string will produce a compiler warning when assigned null with nullable enabled.
Q What is the core difference between record and class?
A record uses value-based equality (== compares content), while class uses reference-based equality (== compares memory address).
Q Can the with expression be used with class?
A No. with only works with record types or structs with init-only properties.
Q Is there a limit on the number of tuple elements?
A ValueTuple supports up to 8 type parameters; beyond that, nested TRest is used for extension.

📖 Summary

📝 Exercises

  1. Declare double? price = null;, use GetValueOrDefault(99.9) to get the default value and output it
  2. Write a method that accepts a string? parameter, uses ?. and ?? to return the string length or -1
  3. Use the is pattern to check if object obj = 3.14; is double d, and output d * 2
  4. Define record Book(string Title, double Price);, create an instance, and use with to modify the price
  5. Use a tuple switch expression to check (int month, int day) for whether it is "New Year's Day" or "National Day"
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏