C# 8 中的不可为空的引用类型在运行时可以为空吗?
Posted
技术标签:
【中文标题】C# 8 中的不可为空的引用类型在运行时可以为空吗?【英文标题】:Can a non-nullable reference type in C# 8 be null in runtime? 【发布时间】:2020-04-19 05:05:53 【问题描述】:在我看来,确实不能保证不可为空的变量永远不会为空。想象一下,我有一个类有一个不可为空的属性:
public class Foo
public Foo(string test)
Test = test;
public string Test get;set;
现在看起来它现在不能为空。但是如果我们用另一个不使用可为空上下文的库来引用这个类,没有什么能阻止它在那里发送 null。
这是正确的还是有一些运行时检查可以确保这一点?
【问题讨论】:
是public void Foo(string test)...
还是public Foo(string test)...
?
谢谢,我已经修好了。当人类过度依赖 R# 来生成构造函数时,就会发生这种情况:)
C# 9 将(可能)添加simplified null validation。
简而言之,“可空引用类型”功能完全被破坏了。
【参考方案1】:
这就是 MS 所说的 (https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/upgrade-to-nullable-references#interfaces-with-external-code):
编译器无法验证对公共 API 的所有调用,即使您的代码是在启用可空注释上下文的情况下编译的。此外,您的库可能会被尚未选择使用可为空引用类型的项目使用。验证公共 API 的输入,即使您已将它们声明为不可空类型。
【讨论】:
【参考方案2】:即使在您自己的代码中,如果您选择这样做,您也可以使用 null-forgiving 运算符传递 null
。就编译器的可空性分析而言,null!
被认为是非空的。
【讨论】:
【参考方案3】:总有人能做到
var myFoo = new Foo(null);
也许你可以使用领域驱动设计
public class Foo
public Foo(string test)
if (string.IsNullOrWhiteSpace(test))
throw new ArgumentNullException(nameof(test));
Test = test;
public string Test get;private set;
【讨论】:
是的,你是对的,我猜这只是一个警告。我希望将来他们可以像在例如科特林【参考方案4】:你是对的,其他没有使用新功能的代码可以将 null 分配给这个属性,没有运行时检查它只是编译器提示。
如果您想要运行时检查,您总是可以自己做:
public string Test get; set if (value == null) throw new ArgumentNullException()
请注意,您可以保证在大部分代码中不为空,您只需向***公共 API 添加防护并确保类被适当密封等。
当然,人们仍然可以使用反射来完善您的代码,但随后它就在他们身上
【讨论】:
所以这实际上意味着即使我确实使用了不可为空的类型,我仍然可以获得空引用异常,对吧? 嗯.... 你不能在你编译的代码中,因为你有提示......但是其他人的代码没有提示开启,但参考您的代码 - 是的,他们可以获得空异常 好吧,例如自动映射器使用你的构造函数,或者类似的东西,仍然是你会得到异常:)Of course people can still use reflection to f*** your code up
,真的,真的。您绝对可以使用反射来做到这一点,是否推荐,否,人们仍然这样做吗,是的。【参考方案5】:
为了处理空检查并使您的代码可读,我建议使用空对象设计模式。
更多阅读:
https://www.c-sharpcorner.com/article/null-object-design-pattern/
基本上,它涉及创建一个从相同接口派生并具有空实例的新对象。
例子:
public class NullExample : IExample
private static NullExample _instance;
private NullExample()
public static NullExample Instance
get
if (_instance == null)
return new NullExample();
return _instance;
//do nothing methods
public void MethodImplementedByInterface1()
public void MethodImplementedByInterface1()
空值是不可避免的,但是可以干净地检查它们。
【讨论】:
以上是关于C# 8 中的不可为空的引用类型在运行时可以为空吗?的主要内容,如果未能解决你的问题,请参考以下文章
C# 8 中的 Non-Nullable 引用类型的默认值是多少?