Improving non-nullable reference types handling

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

内容简介: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:


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

查看所有标签

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

区块链核心算法解析

区块链核心算法解析

【瑞士】Roger Wattenhofer(罗格.瓦唐霍费尔) / 陈晋川、薛云志、林强、祝庆 / 电子工业出版社 / 2017-8 / 59.00

《区块链核心算法解析》介绍了构建容错的分布式系统所需的基础技术,以及一系列允许容错的协议和算法,并且讨论一些实现了这些技术的实际系统。 《区块链核心算法解析》中的主要概念将独立成章。每一章都以一个小故事开始,从而引出该章节的内容。算法、协议和定义都将以形式化的方式描述,以便于读者理解如何实现。部分结论会在定理中予以证明,这样读者就可以明白为什么这些概念或算法是正确的,并且理解它们可以确保实现......一起来看看 《区块链核心算法解析》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具