Improving non-nullable reference types handling

栏目: IT技术 · 发布时间: 4年前

内容简介:A few weeks ago I started usingThe main thing that started getting on my nerves was diagnostic
Improving non-nullable reference types handling

A few weeks ago I started using non-nullable reference types - a new C# language feature which was shipped with version 8.0. It wasn’t a completely new experience for me, because I was working before on projects that were heavily utilizing [NotNull] and [CanBeNull] Resharper annotations . The way how non-nullable types are handled by Roslyn seems to be a little more complex in comparison to Resharper - there are around 40 different diagnostics related to this area. This large amount of inspections is good because it very often brings your attention to the edge cases that you would probably overlook, but on the other hand, it sometimes makes the development more tedious. The project on which I’m working is a greenfield, so I enabled the not-nullable feature on the whole solution scope and set the severity level for all of those rules to error . After a couple of days working with such setup, I got the feeling that I needed to put in much more effort than I was getting out of it.

Problems with non-nullable reference types

The main thing that started getting on my nerves was diagnostic CS8618: Non-nullable field is uninitialized. Consider declaring as nullable. This rule enforces on us mandatory field initialization to guarantee non-nullable value, which can be satisfied by providing the value directly in the field definition or through the containing type’s constructor. In most cases, when there are no constraints to guard beside the nullability check, adding such constructor introduces unnecessary complexity to our codebase, especially for large POCO types.

Improving non-nullable reference types handling

The situation is especially confusing for generic types because CS8618 is reported for generic fields too, even when there is no constraint that suggests the generic type parameter is a reference type.

Improving non-nullable reference types handling

There is a way to dismiss this diagnostic by initializing the field with null! for reference types and default! for generics:

Improving non-nullable reference types handling

But this is rather a dirty hack that hides the real problem instead of solving it. If we want to go that way, then we might as well completely disable CS8618 , for example with the following entry in .editorconfig :

[*.cs]

# CS8618: Non-nullable field is uninitialized. Consider declaring as nullable.
dotnet_diagnostic.CS8618.severity = none

Proposition of improvements

Recently, I’ve been experimenting with Roslyn analyzer that could enforce mandatory initialization via initialization block for members decorated with special attributes. I’ve come up with two attributes [InitRequired] and [InitOnly] - you can read about them in my previous blog post Immutable types in C# with Roslyn . Those attributes basically move the responsibility for field initialization from class creator to class users. Everyone who wants to create a new class instance, is obligated to provide values for all non-nullable reference fields via initialization block. However, using those attributes solves the problem only partially because the compiler still keeps reporting CS8618 diagnostic. To solve that issue, I implemented a dedicated DiagnosticSuppressor which discards CS8618 for fields and properties marked with those properties.

Improving non-nullable reference types handling

If we want to use that approach through the entire codebase, adding an additional attribute to every non-nullable reference field could result in unnecessary noise. It seemed to be an imperfect solution, so I decided to take it on the next level and I introduced [InitRequiredForNotNull] attribute. Applying this attribute on the assembly level results with required initialization via init block for all non-nullable reference fields and properties and automatic discard of CS8618 for all those members.

Improving non-nullable reference types handling

This solution works pretty well also with generics because it enforces mandatory initialization only when the generic parameter is bound to non-nullable reference type:

Improving non-nullable reference types handling

Important:If you like the idea of [InitRequiredForNotNull] attribute and you are going to use it in your project, please make sure that all your teammates know about it.

All attributes and analyzers described here are available as a single Nuget package SmartAnalyzers.CSharpExtensions.Annotations . The source code is published on Github under CSharpExtensions project. Please let me know what you think about those extensions to C# language and if you encounter any problems with using it, feel free to report an issue on Github page.

If you find this blog post useful and you think it's worth to share this idea with others, please don't hesitate to use these buttons below:


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

计算机程序设计艺术(第2卷)

计算机程序设计艺术(第2卷)

Donald E. Knuth / 苏运霖 / 国防工业出版社 / 2002-8 / 98.00元

本书是国内外业界广泛关注的7卷本《计算机程序设计艺术》第2卷的最新版。本卷对半数值算法领域做了全面介绍,分“随机数”和“算术”两章。本卷总结了主要算法范例及这些算法的基本理论,广泛剖析了计算机程序设计与数值分析间的相互联系,其中特别值得注意的是作者对随机数生成程序的重新处理和对形式幂级数计算的讨论。 本书附有大量习题和答案,标明了难易程度及数学概念的使用。 本书内容精辟,语言流畅,引人入胜,可供从......一起来看看 《计算机程序设计艺术(第2卷)》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

URL 编码/解码
URL 编码/解码

URL 编码/解码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具