C# 可空性未正确推断
C# Nullability not deduced correctly
考虑:
#nullable enable
class Manager {
public int Age;
}
class Archive {
readonly Dictionary<string, Manager> Dict = new Dictionary<string, Manager>();
public (bool ok, Manager? value) this[string key] {
get {
return Dict.TryGetValue(key, out var value) ? (true, value) : (false, null);
}
}
}
然后我尝试:
Archive archive = new Archive();
var (ok, john) = archive["John"];
if (!ok) return;
int age = john.Age; // <-- warning
我收到警告:
Warning CS8602 Dereference of a possibly null reference.
为什么?我预计在检查 !ok
之后,编译器会推断出 john
不为 null
我尝试的另一件事是:
public (bool ok, Manager value) this[string key] {
get {
return Dict.TryGetValue(key, out var value) ? (true, value) : default;
}
}
(从管理器结果中删除了 ?
,并将 (false, null)
替换为 default
)
我现在没有收到任何警告,但如果我删除 !ok
.
的检查,我也不会收到任何警告
有什么方法可以实现我在这里想要的 - 一个警告 当且仅当 之前没有检查 !ok
(那是我忘了检查为此)
谢谢
Why ? I expected that after checking for !ok the compiler will deduce that john is not null
这不起作用的原因有两个:
- 可空性分析一次只关注一种方法。
分析时:
Archive archive = new Archive();
var (ok, john) = archive["John"];
if (!ok) return;
int age = john.Age; // <-- warning
编译器看不到这个方法:
public (bool ok, Manager? value) this[string key] {
get {
return Dict.TryGetValue(key, out var value) ? (true, value) : (false, null);
}
}
并告诉 value
在 ok
为真时不为空。
- 可空性分析不跟踪布尔变量。
目前编译器不够智能,无法跟踪布尔变量的来源,并根据它们更新可空性。例如,以下不会发出警告:
M(string? str)
{
if (string != null)
Console.WriteLine(str.Length);
}
但是下面的等效代码可以:
M(string? str)
{
var isNotNull = string != null;
if (isNotNull)
Console.WriteLine(str.Length);
}
Is there any way to achieve what I want here - a warning if and only if there was no previous check for !ok (that is I forgot to check for it)
恐怕不适用于元组。最好的方法是使用 out 参数,尽管这意味着您不能使用索引器:
public bool TryGetManager(string key, [NotNullWhen(true)] Manager? manager)
=> Dict.TryGetValue(key, out manager);
考虑:
#nullable enable
class Manager {
public int Age;
}
class Archive {
readonly Dictionary<string, Manager> Dict = new Dictionary<string, Manager>();
public (bool ok, Manager? value) this[string key] {
get {
return Dict.TryGetValue(key, out var value) ? (true, value) : (false, null);
}
}
}
然后我尝试:
Archive archive = new Archive();
var (ok, john) = archive["John"];
if (!ok) return;
int age = john.Age; // <-- warning
我收到警告:
Warning CS8602 Dereference of a possibly null reference.
为什么?我预计在检查 !ok
之后,编译器会推断出 john
不为 null
我尝试的另一件事是:
public (bool ok, Manager value) this[string key] {
get {
return Dict.TryGetValue(key, out var value) ? (true, value) : default;
}
}
(从管理器结果中删除了 ?
,并将 (false, null)
替换为 default
)
我现在没有收到任何警告,但如果我删除 !ok
.
有什么方法可以实现我在这里想要的 - 一个警告 当且仅当 之前没有检查 !ok
(那是我忘了检查为此)
谢谢
Why ? I expected that after checking for !ok the compiler will deduce that john is not null
这不起作用的原因有两个:
- 可空性分析一次只关注一种方法。
分析时:
Archive archive = new Archive();
var (ok, john) = archive["John"];
if (!ok) return;
int age = john.Age; // <-- warning
编译器看不到这个方法:
public (bool ok, Manager? value) this[string key] {
get {
return Dict.TryGetValue(key, out var value) ? (true, value) : (false, null);
}
}
并告诉 value
在 ok
为真时不为空。
- 可空性分析不跟踪布尔变量。
目前编译器不够智能,无法跟踪布尔变量的来源,并根据它们更新可空性。例如,以下不会发出警告:
M(string? str)
{
if (string != null)
Console.WriteLine(str.Length);
}
但是下面的等效代码可以:
M(string? str)
{
var isNotNull = string != null;
if (isNotNull)
Console.WriteLine(str.Length);
}
Is there any way to achieve what I want here - a warning if and only if there was no previous check for !ok (that is I forgot to check for it)
恐怕不适用于元组。最好的方法是使用 out 参数,尽管这意味着您不能使用索引器:
public bool TryGetManager(string key, [NotNullWhen(true)] Manager? manager)
=> Dict.TryGetValue(key, out manager);