取消引用可能为空的引用...我的代码可以简化吗?
Dereference of a possibly null reference ... Can my code be simplified?
我的项目是 C# 中的 .Net-6 Blazor WebAssembly(托管)。可以简化我的代码以避免出现可为 null 的警告吗?
我想要来自 ApplicationUser 对象的身份名称(变量为“_Name”)的页面变量中的此人的客户 ID。谢谢
List<Person> listPersons = (List<Person>)(await PService.GetPersons()).ToList();
Person oPerson = new Person();
if (listPersons != null){
oPerson = (Person)listPersons.Where(p => p.Name!.Equals(_Name)).FirstOrDefault();
}
if (oPerson != null) {
_UID_CUSTOMER = oPerson.UID_CUSTOMER;
}
您可以通过从 csproj 文件中删除此设置来避免可为 null 的警告
<Nullable>enable</Nullable>
并有这些设置
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
当您使用 Nullable Reference Type feature 时,您需要考虑对于每个(参考)变量,该变量是否允许空值。
这与值类型没有什么不同,例如 int
。你不会做
int a = 5;
if (a != null) { // ... }
因为 a
永远不能为空。您需要使用 int?
数据类型,甚至 allow a
为 null。
诚然,有一些方法可以破坏可空引用类型功能 - 例如忽略警告。
让我们使用您的代码并解决一些问题。我会添加行号。
1 List<Person> listPersons = (List<Person>)(await PService.GetPersons()).ToList();
2 Person oPerson = new Person();
3 if (listPersons != null){
4 oPerson = (Person)listPersons.Where(p => p.Name!.Equals(_Name)).FirstOrDefault();
5 }
6 if (oPerson != null) {
7 _UID_CUSTOMER = oPerson.UID_CUSTOMER;
8 }
第 1 行
await PService.GetPersons()
return 和 IEnumerable<Person>
。因为没有 ?
,这意味着整个对象不能为空。此外,每个元素(流中的每个 Person 对象)都不能为空。如果您真的希望 PService.GetPersons()
给您数据 或 null,则 return 类型将是 Task<IEnumerable<Person>?>
.
将 IEnumerable<Person>
转换为 List<Person>
是危险的。你得到一个 IEnumerable<Person>
,一个接口。底层集合 可以 是一个列表,或者它可以是一个数组,或者其他实现 IEnumerable
的东西。当 PService.GetPersons()
的实现发生变化时,将其转换为 List 可能会导致运行时错误。
运行ToList()
在 转换为 List 之后没有太多意义。它已经是一个列表。事实上,假设您没有获得转换异常,如果 List 为 null,此方法将通过异常。这完全消除了进行空检查的意义。
所以,这是更好的第 1 行:
IEnumerable<Person> people = await PSService.GetPersons();
- 对“人”使用正确的复数形式。
- 保持类型
IEnumerable<Person>
,如果您只打算使用一次流,则无需强制转换为 List。
第 2 行
您将 oPerson
的默认值设置为 Person 的新实例,并且数据类型 (Person
) 表示它永远不能包含空值。但是,在第 4 行,您使用 FirstOrDefault
,其中“默认”将为空。所以我们需要更改数据类型来解决这个问题。
此外,我们将重写第 4 行,使第 4 行始终运行,而第 2 行的变量初始化是不必要的。
事实上,这一整行是不需要的,因为它只是变量名。所以删除它。
第 3 行和第 5 行
检查 listPersons
(现在称为 people
)的可空性没有意义,因为您已经告诉编译器它不能为空。删除那些行。
第 4 行
在您拥有 Name!.Equals()
的地方。 !
是“空宽恕”运算符。问题在于,如果 Name
为 null,则 .Equals()
将抛出异常。将 .Equals
替换为 ==
。 (这都是假设 Name
的数据类型是 string?
)。
最后的演员表也没有必要。 FirstOrDefault
将 return 变成 Person
(或 null),因此将其转换为相同的数据类型是浪费。
Person? oPerson = people.FirstOrDefault(p => p.Name == _Name);
旁注,我不同意将 FirstOrDefault
中的“默认”值设为 Person 的新实例。我的意见是 FirstOrDefault
的默认值应该为空。这对我来说对您的代码具有语义意义。您正在查看列表以找到匹配的人。如果你找不到一个,那么你会得到 null,而不是一些新的空人。
第 6、7 和 8 行
这些都很好。
但是,如果 _UID_CUSTOMER
的值在执行这些行之前已经为空,则可以简化这些行。在这种情况下,所有行都可以替换为:
_UID_CUSTOMER = oPerson?.UID_CUSTOMER;
这意味着:
- 如果 oPerson 为 null,则使用 null
- 如果 oPerson 不为空,则使用 UID_CUSTOMER
的值
同样,只有当您在该行执行之前不关心 _UID_CUSTOMER
的值时才有效。如果只想在oPerson
不为null时覆盖_UID_CUSTOMER
only,改回if语句
所以,把它们放在一起你会得到
IEnumerable<Person> people = await PSService.GetPersons();
Person? oPerson = people.FirstOrDefault(p => p.Name == _Name);
_UID_CUSTOMER = oPerson?.UID_CUSTOMER;
我的项目是 C# 中的 .Net-6 Blazor WebAssembly(托管)。可以简化我的代码以避免出现可为 null 的警告吗? 我想要来自 ApplicationUser 对象的身份名称(变量为“_Name”)的页面变量中的此人的客户 ID。谢谢
List<Person> listPersons = (List<Person>)(await PService.GetPersons()).ToList();
Person oPerson = new Person();
if (listPersons != null){
oPerson = (Person)listPersons.Where(p => p.Name!.Equals(_Name)).FirstOrDefault();
}
if (oPerson != null) {
_UID_CUSTOMER = oPerson.UID_CUSTOMER;
}
您可以通过从 csproj 文件中删除此设置来避免可为 null 的警告
<Nullable>enable</Nullable>
并有这些设置
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
当您使用 Nullable Reference Type feature 时,您需要考虑对于每个(参考)变量,该变量是否允许空值。
这与值类型没有什么不同,例如 int
。你不会做
int a = 5;
if (a != null) { // ... }
因为 a
永远不能为空。您需要使用 int?
数据类型,甚至 allow a
为 null。
诚然,有一些方法可以破坏可空引用类型功能 - 例如忽略警告。
让我们使用您的代码并解决一些问题。我会添加行号。
1 List<Person> listPersons = (List<Person>)(await PService.GetPersons()).ToList();
2 Person oPerson = new Person();
3 if (listPersons != null){
4 oPerson = (Person)listPersons.Where(p => p.Name!.Equals(_Name)).FirstOrDefault();
5 }
6 if (oPerson != null) {
7 _UID_CUSTOMER = oPerson.UID_CUSTOMER;
8 }
第 1 行
await PService.GetPersons()
return 和 IEnumerable<Person>
。因为没有 ?
,这意味着整个对象不能为空。此外,每个元素(流中的每个 Person 对象)都不能为空。如果您真的希望 PService.GetPersons()
给您数据 或 null,则 return 类型将是 Task<IEnumerable<Person>?>
.
将 IEnumerable<Person>
转换为 List<Person>
是危险的。你得到一个 IEnumerable<Person>
,一个接口。底层集合 可以 是一个列表,或者它可以是一个数组,或者其他实现 IEnumerable
的东西。当 PService.GetPersons()
的实现发生变化时,将其转换为 List 可能会导致运行时错误。
运行ToList()
在 转换为 List 之后没有太多意义。它已经是一个列表。事实上,假设您没有获得转换异常,如果 List 为 null,此方法将通过异常。这完全消除了进行空检查的意义。
所以,这是更好的第 1 行:
IEnumerable<Person> people = await PSService.GetPersons();
- 对“人”使用正确的复数形式。
- 保持类型
IEnumerable<Person>
,如果您只打算使用一次流,则无需强制转换为 List。
第 2 行
您将 oPerson
的默认值设置为 Person 的新实例,并且数据类型 (Person
) 表示它永远不能包含空值。但是,在第 4 行,您使用 FirstOrDefault
,其中“默认”将为空。所以我们需要更改数据类型来解决这个问题。
此外,我们将重写第 4 行,使第 4 行始终运行,而第 2 行的变量初始化是不必要的。
事实上,这一整行是不需要的,因为它只是变量名。所以删除它。
第 3 行和第 5 行
检查 listPersons
(现在称为 people
)的可空性没有意义,因为您已经告诉编译器它不能为空。删除那些行。
第 4 行
在您拥有 Name!.Equals()
的地方。 !
是“空宽恕”运算符。问题在于,如果 Name
为 null,则 .Equals()
将抛出异常。将 .Equals
替换为 ==
。 (这都是假设 Name
的数据类型是 string?
)。
最后的演员表也没有必要。 FirstOrDefault
将 return 变成 Person
(或 null),因此将其转换为相同的数据类型是浪费。
Person? oPerson = people.FirstOrDefault(p => p.Name == _Name);
旁注,我不同意将 FirstOrDefault
中的“默认”值设为 Person 的新实例。我的意见是 FirstOrDefault
的默认值应该为空。这对我来说对您的代码具有语义意义。您正在查看列表以找到匹配的人。如果你找不到一个,那么你会得到 null,而不是一些新的空人。
第 6、7 和 8 行
这些都很好。
但是,如果 _UID_CUSTOMER
的值在执行这些行之前已经为空,则可以简化这些行。在这种情况下,所有行都可以替换为:
_UID_CUSTOMER = oPerson?.UID_CUSTOMER;
这意味着:
- 如果 oPerson 为 null,则使用 null
- 如果 oPerson 不为空,则使用 UID_CUSTOMER 的值
同样,只有当您在该行执行之前不关心 _UID_CUSTOMER
的值时才有效。如果只想在oPerson
不为null时覆盖_UID_CUSTOMER
only,改回if语句
所以,把它们放在一起你会得到
IEnumerable<Person> people = await PSService.GetPersons();
Person? oPerson = people.FirstOrDefault(p => p.Name == _Name);
_UID_CUSTOMER = oPerson?.UID_CUSTOMER;