C# Nullable-Typen

In C#,int、float、bool、DateTimeetc. sindWerttyp, sie müssen standardmäßig einen Wert haben und können nichtnull:

int a = null;  // 编译错误:无法将 null 转换为 int

Nullable-Typenlösen dieses Problem – sie verleihen Werttypen einen zusätzlichen Zustand "kein Wert" (d. h.,null), was in Szenarien, in denen Daten fehlen können, sehr nützlich ist, wie z. B. Datenbankfelder und API-Rückgabewerte.

Die Deklaration ist sehr einfach: Fügen Sie ein?:

int? a = null;  // 合法
int? b = 42;    // 合法

hierint?JaNullable<int>syntaktischer Zucker (Kurzform), die beiden sind vollständig äquivalent:

Nullable&lt;int&gt; a = null;   // 完整写法
int? a = null;              // 简写,效果相同

Das folgende Diagramm zeigt, wie Nullable-Typen im Speicher funktionieren – sie verwenden ein zusätzliches Boolean-Flag, um festzuhalten, "ob ein Wert vorhanden ist":

Memory layout of Nullable<T> int (ordinary value type) Value: 42 4 bytes, always has a value Package Nullable<int> (nullable type) HasValue Value 1 byte 4 bytes 5+ bytes total int? x = 42; true ✓ 42 HasValue = true,Value = 42 int? y = null; false ✗ None HasValue = false, accessing Value will throw an exception.

Der Unterschied zwischen dem einzelnen Fragezeichen ? und dem doppelten Fragezeichen ??

Zwei Operatoren im Zusammenhang mit Nullable-Typen in C# werden oft zusammen verwendet, haben aber völlig unterschiedliche Bedeutungen:

Operatoren Name Zweck Beispiel
? Nullable-Typ-Modifizierer Macht Werttypen dazu fähig,null int? i = 3;Äquivalent zuNullable<int> i = new Nullable<int>(3);
?? Null-Coalescing-Operator Wenn die Variablenulleinen Standardwert bereitstellen, wenn int result = i ?? 0;

Ein einfacher Vergleich:

int i;     // 普通值类型,默认值为 0,永远不能是 null
int? ii;   // 可空类型,默认值为 null

Deklaration und Zuweisung von Nullable-Typen

Deklarationssyntax

<data_type>? <variable_name> = null;

Zum Beispiel:

int? age = null;
double? temperature = 36.6;
bool? isActive = new bool?();   // 显式构造,默认为 null
DateTime? birthday = null;

Nullable<T>kann den normalen Bereich seines zugrunde liegenden Werttyps darstellen, plus einennullWert. Zum Beispiel,Nullable<int>kann sein-2,147,483,648auf2,147,483,647jede ganze Zahl dazwischen, odernull。

Vollständiges Beispiel

Beispiel

using System;

namespace NullableDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            // Nullable-Variablen verschiedener Typen deklarieren
            int? num1 = null;
            int? num2 = 45;
            double? num3 = new double?();   // null
            double? num4 = 3.14157;
            bool? boolVal = new bool?();    // null

            // Wert anzeigen (null wird als leerer String angezeigt)
            Console.WriteLine($"num1 = {num1 ?? 0}");         // 0
            Console.WriteLine($"num2 = {num2 ?? 0}");         // 45
            Console.WriteLine($"num3 = {num3 ?? 0.0}");       // 0
            Console.WriteLine($"num4 = {num4 ?? 0.0}");       // 3.14157
            Console.WriteLine($"boolVal = {boolVal}");         // (leer)
        }
    }
}

Ausgabeergebnis:

num1 = 0
num2 = 45
num3 = 0
num4 = 3.14157
boolVal =

Nullzusammenfügungsoperator (??)

??Operator wird verwendet, um einenFallback-Standardwertbereitzustellen. Wenn die linke Seite nichtnullWenn er nicht null ist, gibt er den linken Wert zurück; andernfalls gibt er den rechten Wert zurück:

<表达式1> ?? <表达式2>
  • if<表达式1>ist nichtnull, zurückgeben<表达式1>;
  • andernfalls gibt er zurück<表达式2>。

Seit C# 8.0 können Sie auch??=(Nullzusammenfügungs-Zuweisungsoperator), nur wenn die VariablenullNur zuweisen, wenn:

int? x = null;
x ??= 10;   // x 为 null,赋值为 10
x ??= 20;   // x 已有值 10,不再赋值

Beispiel

using System;

namespace NullableDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            double? num1 = null;
            double? num2 = 3.14157;

            // ?? stellt einen Standardwert bereit
            double result1 = num1 ?? 5.34;   // num1 ist null → gibt 5.34 zurück
            double result2 = num2 ?? 5.34;   // num2 hat einen Wert → gibt 3.14157 zurück

            Console.WriteLine($"num1 ?? 5.34 = {result1}");   // 5.34
            Console.WriteLine($"num2 ?? 5.34 = {result2}");   // 3.14157

            // Verkettete Verwendung: mehrere alternative Werte angeben
            int? a = null;
            int? b = null;
            int? c = 42;
            int value = a ?? b ?? c ?? 0;    // Nacheinander versuchen, schließlich 42 erhalten
            Console.WriteLine($"a ?? b ?? c ?? 0 = {value}"); // 42
        }
    }
}

Ausgabeergebnis:

num1 ?? 5.34 = 5.34
num2 ?? 5.34 = 3.14157
a ?? b ?? c ?? 0 = 42

Gängige Eigenschaften und Methoden von Nullable-Typen

Mitglied Beschreibung Beispiel
.HasValue Überprüft, ob die Variable einen Wert hat (gibtbool) if (num.HasValue) { ... }
.Value Ruft den tatsächlichen Wert ab (wenn ernullLöst eine Ausnahme ausInvalidOperationException) int x = num.Value;
.GetValueOrDefault() Den Wert sicher abrufen; wenn ernullStandardwert des Typs zurückgeben (wie z. B.0) num.GetValueOrDefault()
.GetValueOrDefault(T) Den Wert sicher abrufen; wenn ernullAngegebenen Standardwert zurückgeben num.GetValueOrDefault(100)
?? Null-Coalescing-Operator (syntaktischer Zucker, entsprichtGetValueOrDefault) int result = num ?? 100;

Beispiel

using System;

namespace NullableDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            int? num = null;

            // HasValue + Value (traditioneller Ansatz)
            if (num.HasValue)
                Console.WriteLine($"Wert: {num.Value}");
            else
                Console.WriteLine("num hat keinen Wert");

            // Standardwert sicher abrufen
            Console.WriteLine(num.GetValueOrDefault());      // 0
            Console.WriteLine(num.GetValueOrDefault(99));    // 99
            Console.WriteLine(num ?? 99);                    // 99 (äquivalente Notation)

            // &#x26a0; Hinweis: Der direkte Zugriff auf .Value löst eine Ausnahme aus
            // int x = num.Value; // InvalidOperationException!
        }
    }
}

Praktische Anwendungsszenarien

Nullable-Typen sind in der realen Entwicklung sehr verbreitet, insbesondere beim Umgang mit potenziell fehlenden Daten:

Datenbankfeldzuordnung

Felder in der Datenbank dürfen seinNULL, Nullable-Typen können genau entsprechen:

Benutzer-ID Alter Ob aktiv
1 28 wahr
2 null false
int? age = GetUserAgeFromDB(userId: 2);

// 安全处理 null
string display = age.HasValue
    ? $"用户年龄:{age.Value}"
    : "年龄未知";

// 或者更简洁的写法
string display2 = $"用户年龄:{age ?? 0}";

Optionale Parameter und Konfiguration

// 配置项可能未设置
int? timeout = GetConfigValue("timeout");
int actualTimeout = timeout ?? 30;  // 未设置时使用默认值 30 秒

Verkettete Nullprüfungen (C# 6.0+)

// 使用 ?. 运算符安全访问可能为 null 的对象
string? name = user?.Address?.City?.Name;
// 如果 user、Address、City 中任何一个为 null,结果就是 null,不会抛异常

Zusammenfassung

Funktionen Beispiel Beschreibung
Definieren von Nullable-Typen int? x = null; Äquivalent zuNullable<int>
Ermitteln, ob ein Wert vorhanden ist x.HasValue returntrueoderfalse
Wert abrufen (unsafe) x.Value Wenn esnullLöst eine Ausnahme ausInvalidOperationException
Standardwert abrufen x ?? 0 Wenn esnullDen rechtsseitigen Wert zurückgeben
Den angegebenen Standardwert abrufen x.GetValueOrDefault(10) Wenn esnull10 zurückgeben
Nullzusammenfügungszuweisung x ??= 10 Nur wennxistnullzuweisen, wenn (C# 8.0+)
Sicherer Navigationszugriff user?.Name ifuseristnulldann zurückgebennull(C# 6.0+)

die "Nullable-Verweistypen" von C# 8.0

Ab C# 8.0 wurde ... eingeführt.Nullable-Verweistypensie und die in diesem Artikel vorgestelltenNullable-Werttypensind zwei verschiedene Mechanismen:

Vergleichspunkt Nullable-Werttypen Nullable-Verweistypen
Beispiel int? string?
Zielobjekt Werttyp (int、bool、structusw.) Verweistypen (string、classArrays usw.)
Implementierungsansatz Zur Laufzeit überNullable<T>Struct-Implementierung Statische Compileranalyse, ändert das Laufzeitverhalten nicht
Standardzustand existiert schon immer (seit C# 1.0) Müssen im Projekt aktiviert werden<Nullable>enable</Nullable>
Nullprüfung Verwenden Sie.HasValueEntscheidungsfindung Der Compiler gibt Warnungen aus (keine Fehler)

Nullable-Verweistypen sind ein Werkzeug zur Prüfung der Kompilierzeitsicherheit — es ändert nicht das Laufzeitverhalten des Programms, aber dort, wo Code möglicherweiseNullReferenceExceptionCompilerwarnungen ausgegeben werden, die Ihnen helfen, potenzielle Probleme während der Entwicklungsphase zu erkennen.

Weitere Erweiterungen