C# 泛型类型和?:运算符不';行不通

C# 泛型类型和?:运算符不';行不通,c#,generics,ternary-operator,C#,Generics,Ternary Operator,有人能解释为什么在使用运算符时此代码失败,但使用if语句吗 下面的代码编译时没有错误。当我运行它时,它抛出一个异常 var myClass = new MyClass<string>(); string tString; //this works fine if (myClass.HasValue) { tString = myClass; } else { tString = null

有人能解释为什么在使用
运算符时此代码失败,但使用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; }
        }
    }
var myClass=new myClass();
串串;
//这个很好用
if(myClass.HasValue)
{
tString=myClass;
}
其他的
{
tString=null;
}
//这将抛出未设置为对象实例的对象引用。
tString=myClass.HasValue?myClass:null;
类MyClass
{
私人T值;
公共价值
{
得到
{
如果(值==null)
{
抛出新异常(“值不能为null”);
}
返回值;
}
设置{this.value=value;}
}
公共静态隐式运算符T(MyClass x)
{
返回x.value;
}
公共布尔值
{
获取{返回值!=null;}
}
}
这里,我们有一个三元。三元数有一个类型,由两个参数确定。编译器查看
myClass
null
,查看它们是否兼容(它们都可以转换为
myClass
),并确定三元类型为
myClass

如果
myClass.HasValue
false
,则我们点击三元函数的
null
分支。然后我们得到一个
MyClass
实例,它是
null
。然后我们需要将其转换为
字符串
:为此,编译器调用隐式运算符,但传入
null
。这会导致
NullReferenceException
,因为您访问
x.value
,但是
x
null

这不会发生在
if/else
中,因为我们从不构造
MyClass
,它是
null
。相反,我们将
null
直接分配给
字符串

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

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

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


OP评论说,显式运算符不会出现这种情况。这是错误的:确实如此

tString = (string)(myClass.HasValue ? myClass : null);
出于相同的原因,这会引发相同的异常

如果您这样做:

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

然后你陷入了和我前面描述的相同的情况,因为你从来没有创建过一个空的
MyClass
,所以你从来没有尝试过将这个
null
MyClass
转换成一个
字符串

将沿着这些行进行注释,但你们两个都比我强,而且解释得比我想象的好。我想补充一点,它只发生在隐式转换中,当使用显式时,它不会发生我的错,当tString=myClass.HasValue时它不会发生?(字符串)myClass:null;或者tString=myClass.HasValue?myClass.Value:空@cinek是的,在这种情况下,您的逻辑与您的
if/else
相同。三元组的类型是
string
,而不是
MyClass
,因此您永远不会创建一个为null的
MyClass
,也永远不会尝试将null
MyClass
转换为字符串。我在早些时候的回答中谈到了这个问题。
tString = myClass.HasValue ? (string)myClass : null;
tString = (string)(myClass.HasValue ? myClass : null);
tString = myClass.HasValue ? (string)myClass : null;