简体   繁体   English

取消引用可能的 null 参考...我的代码可以简化吗?

[英]Dereference of a possibly null reference ... Can my code be simplified?

My project is.Net-6 Blazor WebAssembly (hosted) in C#.我的项目是 C# 中的.Net-6 Blazor WebAssembly(托管)。 Can my code be simplified to avoid nullable warnings?可以简化我的代码以避免可空警告吗? I want the person's customer-ID in a page variable from the ApplicationUser object's Identity Name (variable is '_Name').我希望该人的客户 ID 在来自 ApplicationUser 对象的身份名称(变量是“_Name”)的页面变量中。 Thanks.谢谢。

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;
}

When you work with the Nullable Reference Type feature , you need to consider, for every (reference) variable , whether that variable allows a null.当您使用可空引用类型功能时,您需要考虑,对于每个(引用)变量,该变量是否允许 null。

This is no different than value types, such as int .这与值类型没有什么不同,例如int You wouldn't do你不会做

int a = 5;
if (a != null) { // ... }

because a can never be null.因为a永远不可能是 null。 You'd need to use the int?你需要使用int? datatype to even allow a to be null.数据类型甚至允许a null。

Granted, there are way to break the Nullable Reference Type feature - such as ignoring warnings.当然,有办法打破 Nullable Reference Type 功能 - 例如忽略警告。


Let's take your code and fix some problems.让我们使用您的代码并解决一些问题。 I'll add line numbers.我将添加行号。

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  }

Line 1 1号线

await PService.GetPersons() returns an IEnumerable<Person> . await PService.GetPersons()返回一个IEnumerable<Person> Because there's no ?因为没有? , that means that the whole object cannot be null. ,这意味着整个 object 不能是 null。 In addition, each element (each Person object within the stream) cannot be null.此外,每个元素(流中的每个 Person object)不能是 null。 If you really expect PService.GetPersons() to give you data or null, the return type would be Task<IEnumerable<Person>?> .如果您真的希望PService.GetPersons()为您提供数据null,则返回类型将为Task<IEnumerable<Person>?>

The cast of the IEnumerable<Person> into a List<Person> is dangerous.IEnumerable<Person>转换为List<Person>是危险的。 You get an IEnumerable<Person> , an interface.你得到一个IEnumerable<Person> ,一个接口。 The underlying collection could be a List, or it could be an Array, or something else that implements IEnumerable .底层集合可以是一个列表,也可以是一个数组,或者其他实现IEnumerable的东西。 Casting it to a List can lead to runtime errors when the implementation of PService.GetPersons() changes.PService.GetPersons()的实现发生变化时,将其转换为 List 可能会导致运行时错误。

There's not much point of running ToList() after the cast to a List.在转换为列表之后运行ToList()没有多大意义。 It's already a list.已经是清单了。 In fact, assuming you didn't get a cast exception, this method would through an exception if the List was null.实际上,假设您没有遇到强制转换异常,如果 List 为 null,此方法将通过异常。 This eliminates the point of doing a null check at all.这完全消除了进行 null 检查的意义。

So, here's a better Line 1:所以,这是一个更好的第 1 行:

IEnumerable<Person> people = await PSService.GetPersons();
  • Use the right plural for "person". “人”使用正确的复数形式。
  • Keep the type IEnumerable<Person> , no need to cast to List if you're only going to use the stream once.保留类型IEnumerable<Person> ,如果您只打算使用一次 stream ,则无需转换为 List 。

Line 2 2号线

You set the default of oPerson to a new instance of a Person, and the datatype ( Person ) says that it can never hold a null value.您将oPerson的默认值设置为 Person 的新实例,并且数据类型 ( Person ) 表示它永远不能保存 null 值。 However, on line 4, you use FirstOrDefault , which the "Default" will be null.但是,在第 4 行,您使用FirstOrDefault ,“默认”将为 null。 So we need to change the datatype to account for that.所以我们需要改变数据类型来解决这个问题。

In addition, we're going to rewrite line 4 so that line 4 always runs, and the initialization of the variable on line 2 is unnecessary.此外,我们将重写第 4 行,使第 4 行始终运行,并且不需要在第 2 行初始化变量。

In fact, this whole line is unneeded, because it would just be the varaible name.事实上,这整行是不需要的,因为它只是变量名。 So remove it.所以删除它。

Line 3 and Line 5 3号线和5号线

There's no point in checking the nullability of listPersons (now called people ), because you've told the compiler that it can't be null.检查listPersons (现在称为people )的可空性没有意义,因为您已经告诉编译器它不能是 null。 Remove those lines.删除这些行。

Line 4 4号线

Inside the Where you have Name..Equals() .在 Where you have Name..Equals()中。 The ! ! is the "null forgiveness" operator.是“零宽恕”运算符。 Problem with that is that if Name is null , then .Equals() will throw an exception.问题在于,如果Name是 null ,那么.Equals()将引发异常。 Replace .Equals with == ..Equals替换为== (This is all assuming that the datatype of Name is a string? ). (这都是假设Name的数据类型是string? )。

The cast at the end is also unnecessary.最后的演员阵容也是不必要的。 FirstOrDefault will return a Person (or null), so casting it to the same data type is wasteful. FirstOrDefault将返回一个Person (或 null),因此将其转换为相同的数据类型是浪费的。

Person? oPerson = people.FirstOrDefault(p => p.Name == _Name);

Side note, I don't agree with making the "default" value from FirstOrDefault a new instance of Person.旁注,我不同意将FirstOrDefault中的“默认”值设为 Person 的新实例。 My opinion is that FirstOrDefault 's default should be null.我的观点是FirstOrDefault的默认值应该是 null。 This to me makes semantic sense for your code.对我来说,这对您的代码具有语义意义。 You're looking through a list to find a matching person.您正在查看列表以查找匹配的人。 If you can't find one, then you get null, not some new empty person.如果你找不到一个,那么你会得到 null,而不是一些新的空人。

Lines 6, 7, and 8第 6、7 和 8 行

These are fine.这些都很好。

However, you could simplify the lines if the value of _UID_CUSTOMER was already null before executing these lines.但是,如果_UID_CUSTOMER的值在执行这些行之前已经是 null,则可以简化这些行。 In that case, all the lines could be replaced with:在这种情况下,所有行都可以替换为:

_UID_CUSTOMER = oPerson?.UID_CUSTOMER;

This means:这表示:

  • If oPerson is null, just use null如果oPerson是null,就用null
  • If oPerson is not null, use the value of UID_CUSTOMER如果 oPerson 不是 null,则使用 UID_CUSTOMER 的值

Again, this only works if you didn't care about the value of _UID_CUSTOMER before this line executes.同样,仅当您在执行此行之前不关心_UID_CUSTOMER的值时,这才有效。 If you only want to overwrite _UID_CUSTOMER only when oPerson is not null, change it back to the if statement.如果只想oPerson不是 null 时覆盖_UID_CUSTOMER ,请将其改回 if 语句。


So, putting it all together you get所以,把它们放在一起,你会得到

IEnumerable<Person> people = await PSService.GetPersons();
Person? oPerson = people.FirstOrDefault(p => p.Name == _Name);
_UID_CUSTOMER = oPerson?.UID_CUSTOMER;

You can avoid nullable warning by removing this setting from csproj file您可以通过从 csproj 文件中删除此设置来避免可空警告

<Nullable>enable</Nullable>

And have these settings并有这些设置

<PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>    
    <ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 取消引用 FirstOrDefault 上可能的 null 引用 - Dereference of a possibly null reference on FirstOrDefault 在实体框架 6 查询中取消引用可能的 null 引用 - Dereference of a possibly null reference in Entity Framework 6 query 在 Net6 IF 语句中取消引用可能的 null 引用 - Dereference of a possibly null reference inside Net6 IF statement C# RazorPages EF6,空引用,取消引用可能为空的引用 - C# RazorPages EF6, Null reference, Dereference of a possibly null reference AutoMapping:取消引用可能为空的引用? 空条件运算符不适用于 AutoMapping - AutoMapping: Dereference of a possibly null reference? Null-conditional operator doesn't work with AutoMapping 为什么我在使用非短路 AND 运算符时会取消引用可能的 null 参考警告? - Why do I get dereference of a possibly null reference warning when using non-short-circuit AND operator? 这段代码可以简化吗? - Can this code be simplified? 代码约定静态检查器:可能在空引用上调用方法-为什么? - Code contracts static checker: Possibly calling a method on a null reference — why? C#与Builder模式的代码契约 - “可能在空引用上调用方法” - C# Code Contracts with Builder Pattern - “Possibly calling a method on a null reference” CodeContracts:可能在空引用上调用方法 - CodeContracts: Possibly calling a method on a null reference
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM