当您使用
可空引用类型特性时,需要考虑每个(引用)变量是否允许为 null。
这与值类型(如int)没有区别。您不会这样做。
int a = 5;
if (a != null) { /* ... */ }
因为a
永远不可能为空。你需要使用int?
数据类型,甚至允许a
为空。
当然,有一些方法可以打破可空引用类型的特性 - 比如忽略警告。
让我们拿出你的代码并修复一些问题。我会添加行号。
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 }
第一行
await PService.GetPersons()
返回一个 IEnumerable<Person>
。因为没有 ?
,这意味着整个对象不能为 null。此外,流中的每个元素(每个 Person 对象)也不能为 null。如果您真的希望 PService.GetPersons()
给您数据或 null,则返回类型将是 Task<IEnumerable<Person>?>
。
将 IEnumerable<Person>
强制转换为 List<Person>
是危险的。您得到了一个接口 IEnumerable<Person>
。底层集合可能是 List,也可能是 Array,或者其他实现了 IEnumerable
的东西。将其强制转换为 List 可能会导致运行时错误,当 PService.GetPersons()
的实现发生更改时。
在将对象转换为列表后,运行
ToList()
没有太大意义。它已经是一个列表了。实际上,假设您没有收到强制转换异常,如果列表为空,此方法将抛出异常。这消除了进行空检查的意义。
因此,这是更好的第一行:
IEnumerable<Person> people = await PSService.GetPersons()
- 使用正确的“人”复数形式。
- 保持类型为
IEnumerable<Person>
,如果您只打算使用流一次,则无需强制转换为 List。
第 2 行
您将 oPerson
的默认值设置为 Person 的新实例,并且数据类型 (Person
) 表示它永远不能保存空值。然而,在第 4 行中,您使用了 FirstOrDefault
,其中“Default”将为 null。因此,我们需要更改数据类型以解决这个问题。
此外,我们将重写第 4 行,使第 4 行始终运行,并且第 2 行变量的初始化是不必要的。
事实上,整行都是不必要的,因为它只是变量名。所以把它删掉。
第 3 行和第 5 行
检查 listPersons
(现在称为 people
)是否为空没有意义,因为您告诉编译器它不能为 null。删除这些行。
第 4 行
在
Name!.Equals()
中,
!
是“空值容错”运算符。问题在于,如果
Name
为 null,则
.Equals()
将抛出异常。请用
==
替换
.Equals
。(这一切都假设
Name
的数据类型是
string?
)。
最后的强制转换也是不必要的。
FirstOrDefault
将返回一个
Person
(实际上是一个
Person?
),因此将其强制转换为相同的数据类型是浪费的。
Person? oPerson = people.FirstOrDefault(p => p.Name == _Name)
侧记,我不同意将
FirstOrDefault
的“默认”值设为新的Person实例。我认为
FirstOrDefault
的默认值应该是null。对我来说,这使你的代码在语义上更有意义。你正在查找一个匹配的人物名单。如果找不到,则得到null,而不是一些新的空人。
第6、7和8行
这些很好。
但是,如果
_UID_CUSTOMER
的值在执行这些行之前已经是null,则可以简化这些行。在这种情况下,所有这些行都可以被替换为:
_UID_CUSTOMER = oPerson?.UID_CUSTOMER
这意味着:
- 如果 oPerson 为空,就使用 null
- 如果 oPerson 不为空,则使用 UID_CUSTOMER 的值
再次强调,这仅在此行执行之前不关心 _UID_CUSTOMER 的值时才有效。如果您只想在 oPerson 不为空时覆盖 _UID_CUSTOMER,请将其改回 if 语句。
因此,将所有内容组合在一起,您会得到
IEnumerable<Person> people = await PSService.GetPersons()
Person? oPerson = people.FirstOrDefault(p => p.Name == _Name)
_UID_CUSTOMER = oPerson?.UID_CUSTOMER
listPersons.Where(...)
会返回一个IEnumerable<Person>
类型,你不能将其转换为(Person)
类型。 - Matthew WatsonWhere
过滤listPersons
,会得到一个IEnumerable<Person>
而不是一个Person
。看起来你想要使用.FirstOrDefault
或者.SingleOrDefault
而不是.Where
。 - ProgrammingLlamalistPersons
的数据类型中没有包含?
(例如List<Person>?
),那么你的意思是listPersons
永远不可能为空。请问PService.GetPersons()
的返回类型(特别是该返回类型的可空性)是什么? - gunr2171IEnumerable<Person>
,那就意味着它不可能为空。事实上,即使它确实为空,在 if 语句运行之前.ToList()
就会抛出异常。你对 C# 中的可空引用类型特性了解多少? - gunr2171Name
的数据类型是什么?是string
还是string?
?您允许Name
保存空值吗? - gunr2171