【发布时间】:2023-03-07 23:17:01
【问题描述】:
当我遇到以下情况时,最好的方法是什么?
上下文是一个启用了最新nullable checking 的.NET Core 3.x 应用程序,以及一个带有ref 关键字的方法。真正的代码更复杂,但更简单的版本可能是这样的:
private static bool _initialized = false;
private static object _initializationLock = new object();
private static MyClass _initializationTarget; //suggestion to mark as nullable
public MyClass GetInstance()
{
return LazyInitializer.EnsureInitialized(
ref _initializationTarget,
ref _initialized,
ref _initializationLock,
() => new MyClass()
);
}
EnsureInitialized() 方法采用_initializationTarget 引用,它的开头是null,因此将其标记为可空似乎是正确的调整。但是,相同的方法可以确保正确填充变量。
我找不到比以下更好的模式,但它真的是最好的吗?
private static bool _initialized = false;
private static object _initializationLock = new object();
private static MyClass? _initializationTarget; //marked as nullable
public MyClass GetInstance()
{
//the return value must also nullable
MyClass? inst = LazyInitializer.EnsureInitialized(
ref _initializationTarget,
ref _initialized,
ref _initializationLock,
() => new MyClass()
);
return inst!; //null-forgive here
}
【问题讨论】:
-
能分享一下
LazyInitializer.EnsureInitialized的方法吗? -
这是标准库的一部分:docs.microsoft.com/en-us/dotnet/api/…
-
在我看来,您的方法在这种情况下是最好的。首先,通过将字段
_initializationTarget声明为可为空的引用类型,您隐含地表示它可以包含null值。它使编译器能够检测到它可以为空的用法。例如,如果您声明另一个使用_initializationTarget的方法而不检查它是否为null。其次,方法LazyInitializer.EnsureInitialized不保证返回non-null值。可以返回null有几种情况,比如_initialized是true,_initializationTarget是null。 -
但在您的情况下,您肯定知道
LazyInitializer.EnsureInitialized必须返回non-null值,因为提供的参数保证返回值不会是null。代码分析器不够聪明,无法识别您的情况LazyInitializer.EnsureInitialized保证结果不为空。因此,要满足代码分析器,您必须使用null-forgiving operator。 -
@IliarTurdushev:没有很好的文档记录,但实际上有有重载的
EnsureEnabled()被注释为[NotNull]而不是[MaybeNull]——因此将向编译器保证target引用在执行后不再是null。在这些情况下,不需要容错运算符。不幸的是,该文档不包括可空性属性,并且注释未能突出这种细微差别。我在回答中对此进行了扩展,并附有源代码链接。
标签: c# .net-core .net-core-3.0 c#-8.0 nullable-reference-types