在C#8中,如何检测不可能的空检查? [英] In C# 8, how do I detect impossible null checks?

查看:101
本文介绍了在C#8中,如何检测不可能的空检查?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经开始在C#8中使用可为空的引用类型.到目前为止,除一个小小的事情外,我都喜欢这种改进.

I've started using nullable reference types in C# 8. So far, I'm loving the improvement except for one small thing.

我正在迁移旧的代码库,其中充满了很多冗余或无法访问的代码,例如:

I'm migrating an old code base, and it's filled with a lot of redundant or unreachable code, something like:

void Blah(SomeClass a) {
  if (a == null) {
    // this should be unreachable, since a is not nullable
  }
}

很遗憾,我看不到任何可以为我标记此代码的警告设置!这是Microsoft的疏忽,还是我错过了什么?

Unfortunately, I don't see any warning settings that can flag this code for me! Was this an oversight by Microsoft, or am I missing something?

我也使用ReSharper,但是它的警告设置都没有一个可以捕捉到这一点.还有其他人找到解决方案吗?

I also use ReSharper, but none of its warning settings appear to capture this either. Has anybody else found a solution to this?

我知道从技术上讲这仍然可以实现,因为可空性检查不是防弹的.这不是重点.在这种情况下,我将参数声明为不可为空,通常检查它是否为空是一个错误.在极少数情况下,null作为不可为null的类型传入,我更愿意查看NullReferenceException并跟踪错误地传入null的有害代码.

I'm aware that technically this is still reachable because the nullability checks aren't bulletproof. That's not really the point. In a situation like this, where I declare a paramater as NOT nullable, it is a usually a mistake to check if it's null. In the rare event that null gets passed in as a non-nullable type, I'd prefer to see the NullReferenceException and track down the offending code that passed in null by mistake.

推荐答案

需要特别注意的是,不仅可空性检查不是防弹的,而且旨在使他们劝阻发送null引用后,它们无济于事 prevent .代码仍然可以编译,并向该方法发送null,并且参数值本身没有任何运行时验证.

It's really important to note that not only are the nullability checks not bullet proof, but while they're designed to discourage callers from sending null references, they do nothing to prevent it. Code can still compile that sends a null to this method, and there isn't any runtime validation of the parameter values themselves.

如果您确定所有调用者都将使用C#8的可空性上下文(例如,这是internal方法),并且您是 真的要努力解决Roslyn静态流分析中的所有警告(例如,您已将构建服务器配置为将它们视为错误),那么您就正确地认为这些null检查是多余的.

If you’re certain that all callers will be using C# 8’s nullability context—e.g., this is an internal method—and you’re really diligent about resolving all warnings from Roslyn’s static flow analysis (e.g., you’ve configured your build server to treat them as errors) then you’re correct that these null checks are redundant.

As noted in the migration guide, however, any external code that isn’t using C# nullability context will be completely oblivious to this:

新语法不提供运行时检查.外部代码可能会绕过编译器的流程分析.

The new syntax doesn't provide runtime checking. External code might circumvent the compiler's flow analysis.

鉴于此,通常认为,最好继续在任何publicprotected成员中提供保护子句和其他可为空性检查.

Given that, it’s generally considered a best practice to continue to provide guard clauses and other nullability checks in any public or protected members.

实际上,如果您使用Microsoft的代码分析包-建议-在这种情况下,它会警告您使用保护子句.他们考虑在C#8的可空性上下文中删除此代码,但决定维护出于上述考虑.

In fact, if you use Microsoft’s Code Analysis package—which I’d recommend—it will warn you to use a guard clause in this exact situation. They considered removing this for code in C# 8’s nullability context, but decided to maintain it due to the above concerns.

当您从代码分析"中获得这些警告时,可以像在此处所做的那样将代码包装为空检查.但是您也可以抛出异常.实际上,您可以抛出另一个NullReferenceException-尽管绝对不建议这样做 .在这种情况下,您应该改为抛出ArgumentNullException,并将参数名称传递给构造函数:

When you get these warnings from Code Analysis, you can wrap your code in a null check, as you've done here. But you can also throw an exception. In fact, you could throw another NullReferenceException—though that's definitely not recommended. In a case like this, you should instead throw an ArgumentNullException, and pass the name of the parameter to the constructor:

void Blah(SomeClass a) {
  if (a == null) {
    throw new ArgumentNullException(nameof(a));
  }
  …
}

这比在源头处抛出NullReferenceException更为可取,因为它可以通过明确地命名传递的确切参数(在这种情况下),与调用者沟通他们为避免这种情况可以做的事情作为null.这比仅在发生异常的地方获取NullReferenceException(可能可能对您的内部代码的引用)更有用.

This is much preferred over throwing a NullReferenceException at the source because it communicates to callers what they can do to avoid this scenario by explicitly naming the exact parameter (in this case) that was passed as a null. That's more useful than just getting a NullReferenceException—and, possibly a reference to your internal code—where the exception occurred.

至关重要的是,此异常并不意味着帮助您调试您的代码-这就是代码分析为您所做的.相反,这表明您已经已经识别出了空值的潜在取消引用,并且您已经在源头处对此进行了说明.

Critically, this exception isn't meant to help you debug your code—that's what Code Analysis is doing for you. Instead, it's demonstrating that you've already identified the potential dereference of a null value, and you've accounted for it at the source.

注意:这些保护子句会给您的代码增加很多混乱.我的喜好是创建一个可重用的内部实用程序,该实用程序可以通过单行来处理.另外,上述代码的单行缩写为:

Note: These guard clauses can add a lot of clutter to your code. My preference is to create a reusable internal utility that handles this via a single line. Alternatively, a single-line shorthand for the above code is:

void Blah(SomeClass a) {
  _ = a?? throw new ArgumentNullException(nameof(a));
}

这是回答您最初问题的一种真正的about回方式,即如何检测C#的非空引用类型不必要的空检查的存在.

This is a really roundabout way of answering your original question, which is how to detect the presence of null checks made unnecessary by C#’s non-nullable reference types.

简短的答案是您不能;在这一点上,Roselyn的静态流分析专注于确定取消引用空对象的可能性,而不是检测潜在的无关检查.

The short answer is that you can’t; at this point, Roselyn’s static flow analysis is focused on identifying the possibility of dereferencing null objects, not detecting potentially extraneous checks.

不过,如上所述,答案很长,那就是您不应该;直到Microsoft 添加运行时验证或强制执行可空性上下文之前,这些空检查将继续提供价值.

The long answer, though, as outlined above, is that you shouldn’t; until Microsoft adds runtime validation, or mandates the nullability context, those null checks continue to provide value.

这篇关于在C#8中,如何检测不可能的空检查?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆