首页 > 解决方案 > 如何确保显式运算符在转换null时抛出异常?(不可为空)

问题描述

我在 class 上有一个显式运算符MyVO,它应该是不可为空的。

public class MyVO : ValueObject<MyVO>
{
    public string Value { get; } // Should never be null

    private MyVO(string v) => Value = v;

    public static explicit operator MyVO(string vo)
    {
        if (string.IsNullOrWhiteSpace(vo)) throw new Exception('...');
        return new MyVO(vo);
    }

但是,(MyVO)null不会引发异常。该方法的主体将不会运行。

var myVO = (MyVO)null; // myVO will have the null value

如何确保它不为空?

标签: c#

解决方案


如何确保它不为空?

通过“它”,我假设您的意思是“从nullto 转换的结果MyVO”。如果这不是你的意思,请澄清问题。

你不能。

C# 的一个重要规则是用户定义的转换在与内置转换冲突时永远不会“获胜”。转换null为任何类类型都是合法的,因此MyVO表达式的强制转换null始终导致空引用。如果内置转换有效,编译器甚至不会考虑用户定义的转换。(相信我;我写了那个代码!)

正如 D Stanley 的回答正确指出的那样,如果null是任何类型表达式的string,则调用用户定义的转换;没有内置的 from stringto转换,MyVO因此编译器查找适用的用户定义的转换并找到一个。

因为当你做你正在做的事情时会很痛,所以你应该停止做你正在做的事情。显式转换可能不是实现所需行为的正确方法。

我想我的问题应该是如何使MyVO不可为空。

升级到 C# 8。C# 8 支持对引用类型进行不可为空的注释。

请注意,不可为空的注解应该被正确地认为是注解。类型系统不保证使用不可为空注释注释的变量的值永远不会被观察为空。相反,它会尽力在代码看起来错误时向您发出警告。


当我们查看您的代码时,我注意到您正在使用ValueObject<T>,我假设您是从类似的东西中获得的

https://enterprisecraftsmanship.com/posts/value-object-better-implementation/

让我借此机会提醒您,使用这种模式存在缺陷;您认为想要应用T的约束不是应用到的约束T。我们经常看到这样的事情:

abstract class V<T> where T : V<T>
{
  public void M(T t) { ... }  // M must take an instance of its own type
}

如果我们有class Banana : V<Banana>thenBanana.M作为它的参数 a Banana,这就是我们想要的。但现在假设我们有class Giraffe : V<Banana>. 在这种情况下,Giraffe.M不带长颈鹿;它需要一根香蕉,尽管Giraffe根本没有任何关系Banana

约束并不意味着总是M采用它自己的类的实例。如果您试图在 C# 中构造具有这种约束的泛型类型,则不能;C# 类型系统不够丰富,无法表达该约束。


推荐阅读