Null 是一个百万美元的错误,C# 代码花费了很多精力来消灭这个错误,在 C# 8.0
中引入了 nullable reference types
来解决这个问题。
对于一个值类型,C# 已经有了很好的解决方案,就是 Nullable<T>
的类型,它表示该值可以为 null
也可以是需要的 T
类型的值,一种简写的方案是 T?
,比如 int?
, Datetime?
, Guid?
等等。
但是对于引用类型,它本身就可以表示为 null
,比如说
string s = GetValue();
这里的 s
既可以表示为普通的字符串,也可以表示为一个null
。在 C#
工程文件中,可以通过这种方式开启 NRT
<Nullable>enable</Nullable>
这时候,我们的代码如下
string? s = GetValue();
这时候,编译器知道 s
既可以是普通的字符串,也可以为 null
,如果我们的代码如下
string s = GetValue();
这时候 s
肯定非 null
,换句话说就是 NRT
开启后,普通的引用类型就不能再为 null
。
熟悉 C#
的知道,NRT
同样也是一种语法糖,那么对于这样的代码
int? GetInt() => 1;
string? GetString() => "";
转换成 IL
代码如下
.method private hidebysig instance valuetype [System.Runtime]System.Nullable`1<int32>
GetInt() cil managed
{
.maxstack 8
IL_0000: ldc.i4.1
IL_0001: newobj instance void valuetype [System.Runtime]System.Nullable`1<int32>::.ctor(!0)
IL_0006: ret
}
.method private hidebysig instance string
GetString() cil managed
{
.custom instance void System.Runtime.CompilerServices.NullableContextAttribute::.ctor([in] unsigned int8)
= (01 00 02 00 00)
.maxstack 8
IL_0000: ldstr ""
IL_0005: ret
}
显而易见的是,int?
代码转换成 [System.Runtime]System.Nullable1<int32>
表示,而 string?
则添加了NullableContextAttribute
的注解。 该注解的构造支持三种参数
- 0: 忽视,保持
C# 8
以前版本一致 - 1: 非注解,表示该引用类型不能为 null
- 2: 注解,表示该引用类型可以为 null
通过这种方式,编译器的分析工具就能工作,为代码提供更多 null 检查。工程文件中的 Nullable
元素也有下面四种选择
disable
- 不开启 NRTenabled
- 开启 NRTwarning
- 开始 NRT 不过编译时候出现 Warninganotations
- 只开启?
语法功能
除此之外,也在在单个文件中开启 NRT。
虽然有了 ?
可以帮助编译器分析我们的代码,但是这个还不够,我们需要使用代码注解来提高编译器的分析能力。
public static string? Slugify(string? value)
{
if (value == null)
{
return null;
}
return value.Replace(" ", "-").ToLowerInvariant();
}
Slugify
方法如果传入的参数不为 null
,那么返回值就不是 null
, 这样的代码其实并不需要做 null check
。
var slug = Slugify("This is a test");
Console.WriteLine(slug.Length); /
如果我们在方法中添加代码注解,那么编译器就能知道返回值不为 null.
[return: NotNullIfNotNull("value")]
public static string? Slugify(string? value)
{
// ...
}
var slug = Slugify("This is a test");
Console.WriteLine(slug.Length); // All good! Known to be not null
这里的 [return:NotNullIfNotNull("value")]
告诉编译器,如果 value
参数不为 null
, 则返回值不为 null
,这样就跳过了 null check
。除了这个注解之外,还有更多的注解。
软件开发没有银弹,NRT 是一个非常棒的特性,但是作为一个 breaking-change 的功能,完全采取 NRT
仍然需要大量的工作的要做,一般而言方案如下
- 如果是小的项目,可以直接在工程文件中开启
<Nullable>enable<Nullable>
功能 - 对于大型项目,可以先在工程项目中关闭 NRT,然后依次在文件中开启该功能
- 也可以设置为
warning
, 然后再每个文件中开启,然后逐步解决掉每个 warning.
1、Visual Studio 中浏览 IEnumerable 对象
在 Visual Studio
中如果调试 IEnumerable
对象的时候,通常是比较难受的体验,因为需要挨个查看其中的每个对象。在 Visual Studio 17.2. Preview 2 中,可以使用表格的方式渲染每个对象,每一行是代表每个对象,而每一列则是对象的属性,表格甚至可以用 Excel 打开。
1、MAUI 尝试
Jon Skeet 是 .NET
社区大名鼎鼎的人物,近期尝试了 MAUI
的最新版本,将他之前的 Windows-only
的应用扩展成一个 MacOS
和移动端的应用程序。
总结起来两点:
- 这个一个非常有用的平台,因为它扩展了原本的限制;
- 目前还不是很完善,有很大的改进空间。
.NET 6
将 dotnet format
命令集成进来,这个工具可以帮助我们格式化代码,使他们符合我们定义好的规则,通常这些规则定义在 .editorconfig
文件中,否则就使用一些默认的规则,或者分析器的规则。
虽然目前 IDE 已经集成了这个工程,但是每个 IDE 都是不一样的,而且开发者需要记住这些命令,因此使用
dotnet format
更加是更加好的选择,而
dotnet format --verify-no-changes
可以将违反规则的代码展示出来,并且返回非 0 的返回码,比如说
Run dotnet format --verify-no-changes
Warning: /home/runner/work/dotnet-format/dotnet-format/DotnetFormatExample/Calculator.cs(7,13):
warning IDE0007: use 'var' instead of explicit type
[/home/runner/work/dotnet-format/dotnet-format/DotnetFormatExample/DotnetFormatExample.csproj]
Error: Process completed with exit code 2.
这样可以将 dotnet format
命令集成到 CI 中,这样任何人做出了违反规则的 PR 都失败在 CI 这一步。
作为一个 ASP.NET Core
开发人员,那么如果面试中,问了这些问题,你该如何回答呢?
- 你认为
ASP.NET Core
是一个理想的 Web 应用程序开发框架吗?如果不是,请问它缺失了什么? ASP.NET Core
包含了一个依赖注入,那么你主要到不同的生命周期了吗?他们之间有什么不同?- 你是更加喜欢使用显式的终端路由,还是使用规范的方式?并且说出原因?
- 在
ASP.NET Core
中,还使用哪些第三方的库? - 如果你在网页中定义了一个
Form
, 但是在提交的时候,并没有预期的结果发生,你会如何 debug?
对于 Unity
开发人员来说,C#
是一门必须要掌握的开发语言。但是对于其他游戏开发引擎而言,C++
则是一门更加通用的开发语言,这个教程介绍了 C#
开发人员如何学习 C++
,并且比较他们的异同点。
5、C# 代码规则
Roslyn
是 C# 编译器,它包含了各种代码规范的规则。在开发过程中,打开 Roslyn
分析器可以帮助我们写出更好的代码。
Microsoft Graph 团队分享了代码库从之前的 .NET Framework
迁移到 .NET 6
的过程。结果是显而易见的,在性能上取得了巨大的成功,而且为将来引入更多先进的功能提供了可能。在文章中也给出了迁移的步骤:
- 构建系统现代化
- 准备好架构
- .NET Framework 依赖的库存
- 从项目库中移除
.NET Framework
的依赖 - 避免被 block
- 为新的 Web 服务构建
ASP.NET Core
应用 - 做好
a/b
测试 - 为所有的羡慕迁移至
.NET Core
如何你想要在 .NET
应用程序中运行 Javascript
脚本,该选择那个库完成呢?这篇文章比较了目前比较流行的库,并且发现了一个 JavaScriptEngineSwitcher
库,它可以自由切换这些流行的开源库。
朴素贝叶斯分类是机器学习中一种重要的分类方法, 对于离散型数值分类有着广泛的应用。这篇文章介绍如何使用 C#
实现一个简单的朴素贝叶斯分类器。