任何人都可以解释为什么这个代码在使用?
运算符时失败但是使用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;
在这里,我们有一个三元组。三元组具有一种类型,该类型由两个参数确定。编译器查看myClass
和null
,看到它们是兼容的(它们都可以转换为MyClass<string>
),并确定三元的类型是MyClass<string>
。
如果myClass.HasValue
是false
,那么我们击中了三元组的null
分支。然后,我们得到一个MyClass<string>
实例,这是null
。然后我们需要将其转换为string
:为此,编译器调用隐式运算符但传入null
。这导致你的NullReferenceException
,因为你访问x.value
但x
是null
。
这不会发生在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
。