C#-Null-Bedingungsoperator

Bedingte Anweisungen in C#

In der C#-Programmierung, HandhabungnullDas Prüfen von Werten ist eine häufige, aber fehleranfällige Aufgabe.

traditionellnullDer Prüfcode ist oft ausführlich und mühsam, und der von C# 6.0 eingeführteNull-Bedingungsoperator(?.und?[]) vereinfacht diesen Prozess erheblich.

Der Null-Bedingungsoperator ist syntaktischer Zucker, der mit C# 6.0 eingeführt wurde und es Entwicklern ermöglicht, zuerst zu prüfen, ob das Objekt null ist, bevor auf seine Member oder Elemente zugegriffen wird.nullWenn das Objektnulldas Ergebnis des gesamten Ausdrucks istnullund löst keine Ausnahme ausNullReferenceException。

Grundlegende Syntax

  • ?.- Wird verwendet, um auf Member (Eigenschaften, Methoden, Felder) zuzugreifen
  • ?[]- Wird verwendet, um auf Indexer oder Arrayelemente zuzugreifen
Syntax Beschreibung
a?.b ifaWenn nicht null, zugreifena.b; andernfalls null zurückgeben
a?.Method() ifaWenn nicht null, die Methode aufrufen; andernfalls nichts tun.
a?[i] ifaWenn nicht null, auf den Index zugreifen; andernfalls null zurückgeben.

Warum brauchen wir den Null-Bedingungsoperator?

Probleme mit herkömmlichen Nullprüfungen

Bevor der Null-Bedingungsoperator eingeführt wurde, mussten Entwickler ausführlichen Code schreibennullCode prüfen:

Beispiel

// Traditioneller Ansatz - mühsame Nullprüfungen
string name = null;
if (person != null)
{
    if (person.Address != null)
    {
        if (person.Address.City != null)
        {
            name = person.Address.City.Name;
        }
    }
}

Diese Art von Code ist nicht nur ausführlich, sondern auch fehleranfällig und weniger lesbar.

Vorteile des Null-Bedingungsoperators

Mithilfe des Null-Bedingungsoperators kann dieselbe Logik vereinfacht werden zu:

// 使用 Null 条件运算符 - 简洁明了
string name = person?.Address?.City?.Name;

Wenn ein beliebiger Schritt in einem verketteten Aufruf null istnull, wird der gesamte Ausdruck zurückgebennull, anstatt eine Ausnahme auszulösen.


Detaillierte Syntaxerklärung

1. Memberzugriffsoperator?.

?.Der Operator wird verwendet, um sicher auf die Member (Eigenschaften, Methoden, Felder) eines Objekts zuzugreifen.

Auf Eigenschaft zugreifen

Beispiel

class Person
{
    public string Name { get; set; }
    public Address Address { get; set; }
}

class Address
{
    public string City { get; set; }
}

// Sicherer Zugriff auf Eigenschaften
Person person = null;
string cityName = person?.Address?.City;  // Gibt null zurück, löst keine Ausnahme aus

Methode aufrufen

Beispiel

class Calculator
{
    public int Add(int a, int b) => a + b;
}

Calculator calc = null;
int? result = calc?.Add(5, 3);  // Gibt null zurück, löst keine Ausnahme aus

Zugriff auf Felder

Beispiel

class DataContainer
{
    public string Value;
}

DataContainer container = null;
string value = container?.Value;  // Gibt null zurück, löst keine Ausnahme aus

2. Elementzugriffsoperator?[]

?[]Der Operator wird verwendet, um sicher auf Elemente eines Arrays oder einer Sammlung zuzugreifen.

Zugriff auf Array-Elemente

Beispiel

int[] numbers = null;
int? firstNumber = numbers?[0];  // Gibt null zurück, löst keine Ausnahme aus

numbers = new int[] { 1, 2, 3 };
firstNumber = numbers?[0];  // gibt 1 zurück

Zugriff auf Wörterbuchelemente

Beispiel

Dictionary<string, string> dictionary = null;
string value = dictionary?["key"];  // Gibt null zurück, wirft keine Ausnahme

dictionary = new Dictionary<string, string> { ["key"] = "value" };
value = dictionary?["key"];  // Gibt "value" zurück

Kombination mit anderen Operatoren

Operatoren Name Zweck Beispiel Rückgabewert
? Deklaration eines Nullable-Typs Deklarieren eines Nullable-Werttyps. int? x = null; null
?? Null-Coalescing-Operator Wenn die linke Seite null ist, wird die rechte Seite zurückgegeben. a ?? b b
?. Null-Bedingungsoperator Sicherer Zugriff auf Member a?.b null oder der Wert von b
?[] Null-Bedingungsindexoperator Sicherer Zugriff auf Arrays oder Sammlungen a?[i] null oder das Element
?: Bedingter (ternärer) Operator Abhängig von der Bedingung unterschiedliche Werte zurückgeben a ? b : c b oder c

1. Mit dem Null-Coalescing-Operator??Kombination

Der Null-Bedingungsoperator wird häufig mit dem Null-Coalescing-Operator kombiniert??Zusammen verwenden, um einen Standardwert bereitzustellen:

Person person = null;

// 提供默认值
string cityName = person?.Address?.City ?? "未知城市";
Console.WriteLine(cityName);  // 输出: 未知城市

person = new Person { Address = new Address { City = "北京" } };
cityName = person?.Address?.City ?? "未知城市";
Console.WriteLine(cityName);  // 输出: 北京

Beispiel

using System;

class Address
{
    public string City { get; set; }
}

class Person
{
    public string Name { get; set; }
    public Address Address { get; set; }

    public void SayHello()
    {
        Console.WriteLine($"Hallo, ich bin {Name}");
    }
}

class Program
{
    static void Main()
    {
        Person person = null;

        // Sicherer Zugriff auf Eigenschaften
        Console.WriteLine(person?.Name ?? "Unbenannter Benutzer");

        // Sicher auf verschachtelte Eigenschaften zugreifen
        Console.WriteLine(person?.Address?.City ?? "Unbekannte Stadt");

        // Methoden sicher aufrufen
        person?.SayHello();

        // Sicher auf Arrays zugreifen
        int[] arr = null;
        Console.WriteLine(arr?[0] ?? -1);
    }
}

Ausgabe:

未命名用户
未知城市
-1

2. Mit dem bedingten Operator?:Kombination

Beispiel

Person person = null;
string displayName = person?.Name ?? (person != null ? "Anonymer Benutzer" : “Benutzer existiert nicht”);

3. Verwendung in LINQ-Abfragen

Beispiel

List<Person> people = new List<Person>
{
    new Person { Name = "Zhang San", Address = new Address { City = "Beijing" } },
    new Person { Name = "Li Si", Address = null },
    null
};

// Sicherer Zugriff auf Eigenschaften, die null sein können
var cities = people
    .Where(p => p?.Address?.City != null)
    .Select(p => p.Address.City)
    .ToList();

Praktische Anwendungsszenarien

Szenario 1: Datenbindung und UI-Entwicklung

Beispiel

// Daten sicher in WPF oder ASP.NET binden
public string DisplayAddress => $"{Person?.Address?.City ?? "Unbekannte Stadt"} - {Person?.Address?.Street ?? "Unbekannte Straße"}";

// Methode sicher aufrufen
button.Click += (s, e) =>
{
    viewModel?.SaveCommand?.Execute(null);
};

Szenario 2: Verarbeitung von API-Antworten

Beispiel

public class ApiResponse<T>
{
    public T Data { get; set; }
    public string Error { get; set; }
}

public class User
{
    public string Name { get; set; }
    public Profile Profile { get; set; }
}

public class Profile
{
    public string AvatarUrl { get; set; }
}

// API-Antwort sicher verarbeiten
ApiResponse<User> response = GetUserFromApi();
string avatarUrl = response?.Data?.Profile?.AvatarUrl ?? "default-avatar.png";

Szenario 3: Konfiguration lesen

Beispiel

public class AppConfig
{
    public DatabaseConfig Database { get; set; }
}

public class DatabaseConfig
{
    public string ConnectionString { get; set; }
    public int? Timeout { get; set; }
}

// Konfiguration sicher auslesen
AppConfig config = LoadConfiguration();
string connectionString = config?.Database?.ConnectionString ?? "DefaultConnection";
int timeout = config?.Database?.Timeout ?? 30;

Überlegungen und bewährte Methoden

1. Rückgabewerttypen

Wenn Sie den Null-Bedingungsoperator verwenden, müssen Sie auf den Rückgabetyp des Ausdrucks achten:

Beispiel

Person person = new Person { Name = "Zhang San" };

// Für Werttypen Nullable<T> zurückgeben
int? nameLength = person?.Name?.Length;  // Typ ist int?

// Für Referenztypen den Typ selbst zurückgeben
string name = person?.Name;  // Der Typ ist string

2. Übermäßige Verwendung vermeiden

Obwohl der Null-Bedingungsoperator praktisch ist, sollte er nicht übermäßig verwendet werden:

Beispiel

// Nicht empfohlen - übermäßig verwendet, schwer zu verstehen
var result = obj1?.Property1?.Method1()?.Property2 ?? defaultValue;

// Empfohlen - angemessen zerlegen, Lesbarkeit verbessern
var temp1 = obj1?.Property1;
var temp2 = temp1?.Method1();
var result = temp2?.Property2 ?? defaultValue;

3. Leistungsüberlegungen

Der Null-bedingte Operator ist in der Leistung mit expliziternullPrüfung vergleichbar, aber verkettete Aufrufe erzeugen temporäre Variablen:

Beispiel

// Diese beiden Ansätze haben eine vergleichbare Leistung
// Methode 1: Traditionelle Prüfung
if (person != null && person.Address != null)
{
    return person.Address.City;
}

// Methode 2: Null-bedingter Operator
return person?.Address?.City;

4. Kombination mit Ereignisaufruf

Der Null-bedingte Operator eignet sich besonders für den Ereignisaufruf:

Beispiel

// Traditionelle Methode
public event EventHandler SomethingHappened;

protected virtual void OnSomethingHappened()
{
    if (SomethingHappened != null)
    {
        SomethingHappened(this, EventArgs.Empty);
    }
}

// Verwendung des Null-Conditional-Operators - prägnanter
protected virtual void OnSomethingHappened()
{
    SomethingHappened?.Invoke(this, EventArgs.Empty);
}

Übungsaufgaben

Übung 1: Refactoring von Code

Der folgende traditionellenullRefaktorisieren Sie den Prüfcode, um den Null-Conditional-Operator zu verwenden:

Beispiel

// ursprünglicher Code
public string GetUserEmail(User user)
{
    if (user != null)
    {
        if (user.Profile != null)
        {
            if (user.Profile.ContactInfo != null)
            {
                return user.Profile.ContactInfo.Email;
            }
        }
    }
    return "Keine E-Mail-Informationen";
}

// Dein refaktorierter Code
public string GetUserEmail(User user)
{
    return user?.Profile?.ContactInfo?.Email ?? "Keine E-Mail-Informationen";
}

Übung 2: Umgang mit Sammlungsdaten

Beispiel

public class Order
{
    public List<OrderItem> Items { get; set; }
    public Customer Customer { get; set; }
}

public class OrderItem
{
    public Product Product { get; set; }
    public int Quantity { get; set; }
}

public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}

public class Customer
{
    public string Name { get; set; }
}

// Schreibe eine Methode, um sicher den Produktnamen in der Bestellung abzurufen.
public string GetFirstProductName(Order order)
{
    return order?.Items?.FirstOrDefault()?.Product?.Name ?? "Keine Produktinformationen";
}

Übung 3: Umfassende Anwendung

Beispiel

// Erstellen Sie ein vollständiges Beispiel, das die Anwendung des Null-Bedingungsoperators in einem realen Projekt demonstriert.
public class ShoppingCart
{
    public List<CartItem> Items { get; set; }
    public decimal? CalculateTotal()
    {
        return Items?.Sum(item => item?.Product?.Price * item?.Quantity) ?? 0;
    }
}

public class CartItem
{
    public Product Product { get; set; }
    public int? Quantity { get; set; }
}

Bedingte Anweisungen in C#

Weitere Erweiterungen