C#-Null-Bedingungsoperator
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
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
{
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
{
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
{
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? 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
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
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
string displayName = person?.Name ?? (person != null ? "Anonymer Benutzer" : “Benutzer existiert nicht”);
3. Verwendung in LINQ-Abfragen
Beispiel
{
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
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 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 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
// 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
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
// 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
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
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 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
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; }
}