通用类型和 ?: 运算符不起作用

Generic type and ?: operator doesn't work

任何人都可以解释为什么这段代码在使用 ? 运算符时失败但与 if 语句一起使用吗?

下面的代码编译没有错误。当我 运行 它抛出一个异常。

    var myClass = new MyClass<string>();

    string tString;
    //this works fine
    if (myClass.HasValue)
    {
        tString = myClass;
    }
    else
    {
        tString = null;
    }
    //this throws Object reference not set to an instance of an object.
    tString = myClass.HasValue ? myClass : null;

    class MyClass<T>
    {
        private T value;
        public T Value
        {
            get
            {
                if(value == null)
                {
                    throw new Exception("Value cannot be null");
                }

                return value;
            }
            set { this.value = value; }
        }
        public static implicit operator T(MyClass<T> x)
        {
            return x.value;
        }
        public bool HasValue
        {
            get { return value != null; }
        }
    }
tString = myClass.HasValue ? myClass : null;

在这里,我们有一个三元组。三元有一个类型,由两个参数决定。编译器查看 myClassnull,发现它们是兼容的(它们都可以转换为 MyClass<string>),并确定三元类型是 MyClass<string>.

如果myClass.HasValuefalse,那么我们就命中了三元的null分支。然后我们得到一个 MyClass<string> 实例,它是 null。然后我们需要将其转换为 string:为此,编译器调用您的隐式运算符但传入 null。这会导致你的 NullReferenceException 因为你访问 x.valuexnull.

if/else 不会发生这种情况,因为我们从未构造 MyClass<string>null。相反,我们将 null 直接分配给 string.

这个更简单的示例出于相同的原因导致相同的异常:

MyClass<string> myClass = null;
string s = myClass;

您还可以通过强制三元类型为 string 而不是 MyClass<string> 来看到这一点,方法是:

tString = myClass.HasValue ? myClass : (string)null;

tString = myClass.HasValue ? (string)myClass : null;

在这种情况下不会发生异常。


OP 评论说这不会发生在显式运算符上。这是错误的:确实如此。

tString = (string)(myClass.HasValue ? myClass : null);

出于同样的原因,这会抛出同样的异常。

如果你这样做:

tString = myClass.HasValue ? (string)myClass : null;

然后你就陷入了我之前描述的同样的情况,因为你从来没有创建一个空的 MyClass<string>,所以你永远不会尝试转换这个 null MyClass<string> 变成 string.