C# 如何确保显式运算符在转换null时引发异常?(不可为空)

C# 如何确保显式运算符在转换null时引发异常?(不可为空),c#,C#,我在类MyVO上有一个显式运算符,它应该是不可为null的 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 (s

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

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);
    }
如何确保它不是null?

null可以隐式转换为任何引用类型,因此编译器不使用显式强制转换运算符。试一试

string s = null;
o = (MyVO)s;
或者直接插入它

o = (MyVO)((string)s);
如何确保它不是空的

我想你指的是从null到MyVO的转换结果。如果这不是你的意思,请澄清问题

你不能

C语言的一条重要规则是,当用户定义的转换与内置转换冲突时,它永远不会获胜。将null转换为任何类类型是合法的,因此对表达式null的MyVO强制转换将始终导致null引用。如果内置转换工作,编译器甚至不考虑用户定义的转换。相信我;我写的代码

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

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

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

升级到c8。C8支持引用类型上不可为空的注释

请注意,不可为null的注释应正确地视为注释。类型系统不能保证用不可为null的注释注释的变量的值永远不会被观察到为null。相反,当代码看起来是错误的时,它会尽力警告您

当我们查看您的代码时,我注意到您正在使用ValueObject,我假设您是从以下内容获得的

让我借此机会提醒大家,使用这种模式存在陷阱;您认为或希望应用于T的约束不是应用于T的约束。我们经常看到这样的情况:

abstract class V<T> where T : V<T>
{
  public void M(T t) { ... }  // M must take an instance of its own type
}
如果我们有类Banana:V,那么Banana.M将香蕉作为它的参数,这就是我们想要的。但是现在假设我们有类Giraffe:V。在这个场景中,Giraffe.M不接受长颈鹿;它需要一根香蕉,即使长颈鹿和香蕉没有任何关系


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

可能应该是MyMvostrings。@WiktorZychla谢谢。修正。嗯,我想我的问题应该是如何使MyVO不可为空。@EricLippert谢谢你的澄清。永远感谢您的专家见解。@EricLippert旁注-大约15年前,我在微软MVP会议上见过您。你和我和一大群人一起吃晚饭,谈论从西雅图天气到语言设计和编译理论的一切。我非常喜欢这次对话,从那以后也一直很喜欢你的见解。创建一个静态FromString方法和文档,这是正确的方法。根本不提供显式运算符。
abstract class V<T> where T : V<T>
{
  public void M(T t) { ... }  // M must take an instance of its own type
}