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

时间:2019-03-13 16:49:56

标签: c# generics ternary-operator

谁能解释为什么使用?运算符但使用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; }
        }
    }

1 个答案:

答案 0 :(得分:11)

tString = myClass.HasValue ? myClass : null;

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

如果MyClass<string>myClass.HasValue,则我们点击三元组的false分支。然后,我们得到一个null的{​​{1}}实例。然后,我们需要将其转换为MyClass<string>:为此,编译器将调用您的隐式运算符,但会传入null。这会导致您的string,因为您访问了null,但是NullReferenceExceptionx.value

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

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

null

您还可以通过执行以下操作,通过将三元类型强制为null而不是string来查看此信息

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

string

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


OP表示对于显式运算符不会发生这种情况。这是错误的:确实如此。

MyClass<string>

出于相同的原因,这将引发相同的异常。

如果相反,您这样做:

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

然后,您陷入了与我之前描述的情况相同的情况,因为您从未创建为null的tString = myClass.HasValue ? (string)myClass : null; ,因此也从未尝试将tString = (string)(myClass.HasValue ? myClass : null); tString = myClass.HasValue ? (string)myClass : null; 转换为MyClass<string>