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

问题描述 投票:4回答:1

任何人都可以解释为什么这个代码在使用?运算符时失败但是使用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; }
        }
    }
c# generics ternary-operator
1个回答
11
投票
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;

然后你会陷入我之前描述的相同的情况,因为你永远不会创建一个null的MyClass<string>,所以你永远不会尝试将这个null MyClass<string>转换为string

© www.soinside.com 2019 - 2024. All rights reserved.