C#のNull条件演算子
C#プログラミングにおいて、処理nullnull チェックは一般的ですが、エラーを起こしやすいタスクです。
伝統のなnullチェックコードは冗長で面倒なことが多く、C# 6.0 で導入されたNull条件演算子(?.と?[])このプロセスを大幅に簡素化します。
Null 条件演算子は C# 6.0 で導入されたシンタックスシュガーであり、開発者がオブジェクトのメンバーや要素にアクセスする前に、そのオブジェクトが null であるかどうかを先にチェックすることを可能にします。null。オブジェクトがnull、式全体の結果はnull、例外はスローされませんNullReferenceException。
基本语法
?.- メンバー(プロパティ、メソッド、フィールド)にアクセスするために使用される?[]- インデクサーまたは配列要素にアクセスするために使用
| 语法 | 说明 |
|---|---|
a?.b |
如果anullでない場合、アクセスa.b。それ以外の場合はnullを返します |
a?.Method() |
如果anull でない場合はメソッドを呼び出し、それ以外の場合は何もしない |
a?[i] |
如果anull でない場合はインデックスにアクセスし、それ以外の場合は null を返す |
なぜ Null 条件演算子が必要なのか?
従来のnullチェックの問題
Null 条件演算子が登場する前、開発者は冗長なコードを書く必要がありましたnull检查代码:
实例
string name = null;
if (person != null)
{
if (person.Address != null)
{
if (person.Address.City != null)
{
name = person.Address.City.Name;
}
}
}
このようなコードは冗長なだけでなく、エラーを起こしやすく、可読性も低くなります。
Null条件演算子の利点
Null 条件演算子を使用すると、同じロジックを簡素化できます:
// 使用 Null 条件运算符 - 简洁明了 string name = person?.Address?.City?.Name;
チェーン呼び出しの中のいずれかの段階が null の場合null、式全体が返されますnull、例外をスローすることはありません。
詳細な構文説明
1. メンバーアクセス演算子?.
?.演算子は、オブジェクトのメンバー(プロパティ、メソッド、フィールド)に安全にアクセスするために使用されます。
访问属性
实例
{
public string Name { get; set; }
public Address Address { get; set; }
}
class Address
{
public string City { get; set; }
}
// 安全访问属性
Person person = null;
string cityName = person?.Address?.City; // 返回 null,不会抛出异常
调用方法
实例
{
public int Add(int a, int b) => a + b;
}
Calculator calc = null;
int? result = calc?.Add(5, 3); // 返回 null,不会抛出异常
访问字段
实例
{
public string Value;
}
DataContainer container = null;
string value = container?.Value; // 返回 null,不会抛出异常
2. 要素アクセス演算子?[]
?[]演算子は、配列やコレクションの要素に安全にアクセスするために使用されます。
配列要素へのアクセス
实例
int? firstNumber = numbers?[0]; // 返回 null,不会抛出异常
numbers = new int[] { 1, 2, 3 };
firstNumber = numbers?[0]; // 返回 1
辞書要素へのアクセス
实例
string value = dictionary?["key"]; // 返回 null,不会抛出异常
dictionary = new Dictionary<string, string> { ["key"] = "value" };
value = dictionary?["key"]; // 返回 "value"
他の演算子との組み合わせ使用
| 运算符 | 名称 | 用途 | 示例 | 返回值 |
|---|---|---|---|---|
? |
null許容型の宣言 | null を許容する値型を宣言する | int? x = null; |
null |
?? |
Null合体演算子 | 左側が null の場合は右側を返す | a ?? b |
b |
?. |
Null条件演算子 | メンバーへの安全なアクセス | a?.b |
nullまたはbの値 |
?[] |
Null条件インデックス演算子 | 配列やコレクションへの安全なアクセス | a?[i] |
nullまたは要素 |
?: |
条件(三項)演算子 | 条件に応じて異なる値を返す | a ? b : c |
b 或 c |
1. Null合体演算子との併用??结合
Null 条件演算子は、しばしば Null 合体演算子と組み合わせて使用されます??一緒に使用して、デフォルト値を提供します:
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); // 输出: 北京
实例
class Address
{
public string City { get; set; }
}
class Person
{
public string Name { get; set; }
public Address Address { get; set; }
public void SayHello()
{
Console.WriteLine($"こんにちは、私は{Name}です");
}
}
class Program
{
static void Main()
{
Person person = null;
// 安全访问属性
Console.WriteLine(person?.Name ?? "未命名用户");
// 安全访问嵌套属性
Console.WriteLine(person?.Address?.City ?? "未知城市");
// 安全调用方法
person?.SayHello();
// 安全访问数组
int[] arr = null;
Console.WriteLine(arr?[0] ?? -1);
}
}
输出:
未命名用户 未知城市 -1
2. 条件演算子との併用?:结合
实例
string displayName = person?.Name ?? (person != null ? "匿名用户" : "ユーザーが存在しません");
3. LINQクエリでの使用
实例
{
new Person { Name = "张三", Address = new Address { City = "北京" } },
new Person { Name = "李四", Address = null },
null
};
// null の可能性があるプロパティに安全にアクセスする
var cities = people
.Where(p => p?.Address?.City != null)
.Select(p => p.Address.City)
.ToList();
実際の適用シナリオ
シナリオ 1:データバインディングと UI 開発
实例
public string DisplayAddress => $"{Person?.Address?.City ?? "未知城市"} - {Person?.Address?.Street ?? "未知街道"}";
// 安全地调用方法
button.Click += (s, e) =>
{
viewModel?.SaveCommand?.Execute(null);
};
シナリオ2:APIレスポンス処理
实例
{
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 响应
ApiResponse<User> response = GetUserFromApi();
string avatarUrl = response?.Data?.Profile?.AvatarUrl ?? "default-avatar.png";
シナリオ3:設定の読み取り
实例
{
public DatabaseConfig Database { get; set; }
}
public class DatabaseConfig
{
public string ConnectionString { get; set; }
public int? Timeout { get; set; }
}
// 安全读取配置
AppConfig config = LoadConfiguration();
string connectionString = config?.Database?.ConnectionString ?? "DefaultConnection";
int timeout = config?.Database?.Timeout ?? 30;
注意事項とベストプラクティス
1. 戻り値の型
Null 条件演算子を使用する際は、式の戻り値の型に注意する必要があります:
实例
// 値型の場合は、Nullable<T> を返す
int? nameLength = person?.Name?.Length; // 型は int?
// 参照型の場合、型自体を返します
string name = person?.Name; // 型は string
2. 過度な使用を避ける
Null 条件演算子は便利ですが、過度に使用すべきではありません:
实例
var result = obj1?.Property1?.Method1()?.Property2 ?? defaultValue;
// 推荐 - 适当分解,提高可读性
var temp1 = obj1?.Property1;
var temp2 = temp1?.Method1();
var result = temp2?.Property2 ?? defaultValue;
3. パフォーマンスの考慮
Null 条件演算子はパフォーマンスの面で、明示的なnullチェックとほぼ同等ですが、チェーン呼び出しは一時変数を作成します:
实例
// 方式 1: 传统检查
if (person != null && person.Address != null)
{
return person.Address.City;
}
// 方式 2: Null 条件运算符
return person?.Address?.City;
4. イベント呼び出しとの組み合わせ
Null 条件演算子は、イベント呼び出しに特に適しています:
实例
public event EventHandler SomethingHappened;
protected virtual void OnSomethingHappened()
{
if (SomethingHappened != null)
{
SomethingHappened(this, EventArgs.Empty);
}
}
// 使用 Null 条件运算符 - 更简洁
protected virtual void OnSomethingHappened()
{
SomethingHappened?.Invoke(this, EventArgs.Empty);
}
实践练习
演習1:コードのリファクタリング
将以下传统nullチェックコードを Null 条件演算子を使用するようにリファクタリングする:
实例
public string GetUserEmail(User user)
{
if (user != null)
{
if (user.Profile != null)
{
if (user.Profile.ContactInfo != null)
{
return user.Profile.ContactInfo.Email;
}
}
}
return "无邮箱信息";
}
// あなたのリファクタリングコード
public string GetUserEmail(User user)
{
return user?.Profile?.ContactInfo?.Email ?? "无邮箱信息";
}
練習2:コレクションデータの処理
实例
{
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; }
}
// 注文の最初の商品の名前を安全に取得するメソッドを作成する
public string GetFirstProductName(Order order)
{
return order?.Items?.FirstOrDefault()?.Product?.Name ?? "无商品信息";
}
演習3:総合応用
实例
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; }
}