检查 "possibly null" 引用的正确方法是什么?
What is the correct way to check for "possibly null" references?
我有这段相关代码:
if (boardMap[i,j] != null) {
Console.Write(boardMap[i,j].color.ToString() + " " + boardMap[i,j].type.ToString());
}
else {
Console.Write("X");
}
boardMap
包含潜在的空值,这就是我实施 if
语句检查 boardMap[i,j]
项是否为空的原因。但是,我在第 2 行收到一条警告,告诉我 boardMap[i,j]
可能为空。
我该如何解决这个问题 -> 像这样进行空值检查的正确方法是什么?
(请注意,我是 dotnet 和 C# 的初学者)
目前编译器不能很好地处理这种情况(和数组 in general). To help compiler determine the null-state of the item you can use pattern matching with empty property pattern:
if (boardMap[i,j] is {} map)
{
Console.Write(map.color.ToString() + " " + map.type.ToString());
}
else
{
Console.Write("X");
}
或者引入一个变量:
var map = boardMap[i,j];
if (map != null)
{
...
}
从 C# 8.0 及更高版本开始,您可以使用 null-forgiving operator。只是追加!在任何可能为空之后。它基本上告诉编译器它应该关闭这种情况的可能为空的警告。
if (boardMap[i,j] != null) {
Console.Write(boardMap[i,j]!.color.ToString() + " " + boardMap[i,j]!.type.ToString());
}
else {
Console.Write("X");
}
尽管您 if
,编译器无法推断 boardMap[i,j]
不会为 null,因此会发出此警告。
编辑
@GuruStron 指出这种警告仅在 C#8 之后发出。我找不到这方面的参考,但我倾向于相信它。这意味着如果有人有这个问题,他至少使用 C#8。
您通常可以根据需要以不同的方式处理此类问题。
使用属性向编译器发出变量不会为空的信号。参见 https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/nullable-analysis
还有这个问题:
使用可为空的引用类型。参见 https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references
使用 !
或 ?
和 ??
运算符或其他答案建议更改代码,使编译器不会发出警告。
忽略编译器警告,因为你知道得更多。
在多线程应用程序中,boardMap[i,j]
可能会在您检查它不为 null 后 10 纳秒设置为 null。这就是(可能)编译器现在抱怨的原因。
当然这取决于你的代码。
如果您确定该数组仅由一个线程处理,则您的 null 检查是安全的,您可以忽略此处的警告。
在多线程场景(无锁定)中保护您的代码的一种简单方法是将数组值分配给局部变量。并对该变量进行空检查和 Console.Write
。那么空检查是安全的。参见@GuruStron post
我有这段相关代码:
if (boardMap[i,j] != null) {
Console.Write(boardMap[i,j].color.ToString() + " " + boardMap[i,j].type.ToString());
}
else {
Console.Write("X");
}
boardMap
包含潜在的空值,这就是我实施 if
语句检查 boardMap[i,j]
项是否为空的原因。但是,我在第 2 行收到一条警告,告诉我 boardMap[i,j]
可能为空。
我该如何解决这个问题 -> 像这样进行空值检查的正确方法是什么?
(请注意,我是 dotnet 和 C# 的初学者)
目前编译器不能很好地处理这种情况(和数组 in general). To help compiler determine the null-state of the item you can use pattern matching with empty property pattern:
if (boardMap[i,j] is {} map)
{
Console.Write(map.color.ToString() + " " + map.type.ToString());
}
else
{
Console.Write("X");
}
或者引入一个变量:
var map = boardMap[i,j];
if (map != null)
{
...
}
从 C# 8.0 及更高版本开始,您可以使用 null-forgiving operator。只是追加!在任何可能为空之后。它基本上告诉编译器它应该关闭这种情况的可能为空的警告。
if (boardMap[i,j] != null) {
Console.Write(boardMap[i,j]!.color.ToString() + " " + boardMap[i,j]!.type.ToString());
}
else {
Console.Write("X");
}
尽管您 if
,编译器无法推断 boardMap[i,j]
不会为 null,因此会发出此警告。
编辑 @GuruStron 指出这种警告仅在 C#8 之后发出。我找不到这方面的参考,但我倾向于相信它。这意味着如果有人有这个问题,他至少使用 C#8。
您通常可以根据需要以不同的方式处理此类问题。
使用属性向编译器发出变量不会为空的信号。参见 https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/nullable-analysis 还有这个问题:
使用可为空的引用类型。参见 https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references
使用
!
或?
和??
运算符或其他答案建议更改代码,使编译器不会发出警告。忽略编译器警告,因为你知道得更多。
在多线程应用程序中,boardMap[i,j]
可能会在您检查它不为 null 后 10 纳秒设置为 null。这就是(可能)编译器现在抱怨的原因。
当然这取决于你的代码。
如果您确定该数组仅由一个线程处理,则您的 null 检查是安全的,您可以忽略此处的警告。
在多线程场景(无锁定)中保护您的代码的一种简单方法是将数组值分配给局部变量。并对该变量进行空检查和 Console.Write
。那么空检查是安全的。参见@GuruStron post