有什么方法可以通过某些 属性 来使可空引用推断为非空,以确保它不是?
Any way to make nullable references deduce being non-null via some property that ensures that it is not?
假设我们有这个 MCVE
class Person
{
public int? Age;
public string? Name;
public bool IsInvalid => Name == null || Age == null;
// ...
public void Something(Person other)
{
if (other.IsInvalid)
return;
Console.WriteLine(other.Name);
Console.WriteLine(other.Age);
}
}
这会向我抱怨,因为编译器宁愿在 if
语句中包含 属性 的表达式。
在我的实际代码中,我有这样的条件,但 属性 使其比检查一系列空值更具可读性。是否有一些属性或我可以做的事情让编译器意识到 属性 给我非空值?
我也完全理解,这对于编译器来说可能是一项非常重要的任务,因此现在可能无法实现。
这也是通过 .NET Core 3.0 Preview 9 完成的,因此在撰写本文时,我可以访问所有可能存在的属性。
首先,年龄和姓名是字段,不是属性。这很重要,因为这意味着不能使用仅适用于属性的属性,例如 NotNullIfNotNull。
在任何情况下,属性用于指定特定代码(方法、getter、setter 等)的前置条件和 post 条件,而不是对象不变量。没有属性可以将一个 属性 的可空性与另一个的值联系起来。
另一方面,NotNullWhen 可用于将方法的参数与其 return 值联系起来,例如:
public bool GetValidValues([NotNullWhen(true)]out int? age, [NotNullWhen(true)]out string? name)
{
age=Age;
name=Name;
return !IsInvalid;
}
使用 GetValidValues
不会生成任何可空性警告;
public void Something(Person other)
{
if (!other.GetValidValues(out var age,out var name))
return;
Console.WriteLine(name.Length);
Console.WriteLine(age);
}
假设我们有这个 MCVE
class Person
{
public int? Age;
public string? Name;
public bool IsInvalid => Name == null || Age == null;
// ...
public void Something(Person other)
{
if (other.IsInvalid)
return;
Console.WriteLine(other.Name);
Console.WriteLine(other.Age);
}
}
这会向我抱怨,因为编译器宁愿在 if
语句中包含 属性 的表达式。
在我的实际代码中,我有这样的条件,但 属性 使其比检查一系列空值更具可读性。是否有一些属性或我可以做的事情让编译器意识到 属性 给我非空值?
我也完全理解,这对于编译器来说可能是一项非常重要的任务,因此现在可能无法实现。
这也是通过 .NET Core 3.0 Preview 9 完成的,因此在撰写本文时,我可以访问所有可能存在的属性。
首先,年龄和姓名是字段,不是属性。这很重要,因为这意味着不能使用仅适用于属性的属性,例如 NotNullIfNotNull。
在任何情况下,属性用于指定特定代码(方法、getter、setter 等)的前置条件和 post 条件,而不是对象不变量。没有属性可以将一个 属性 的可空性与另一个的值联系起来。
另一方面,NotNullWhen 可用于将方法的参数与其 return 值联系起来,例如:
public bool GetValidValues([NotNullWhen(true)]out int? age, [NotNullWhen(true)]out string? name)
{
age=Age;
name=Name;
return !IsInvalid;
}
使用 GetValidValues
不会生成任何可空性警告;
public void Something(Person other)
{
if (!other.GetValidValues(out var age,out var name))
return;
Console.WriteLine(name.Length);
Console.WriteLine(age);
}