谁能解释为什么使用?
运算符但使用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; }
}
}
答案 0 :(得分:11)
tString = myClass.HasValue ? myClass : null;
在这里,我们有一个三元组。三元数具有一个类型,该类型由两个参数确定。编译器查看myClass
和null
,发现它们是兼容的(它们都可以转换为MyClass<string>
),并确定三元类型为{{1} }。
如果MyClass<string>
是myClass.HasValue
,则我们点击三元组的false
分支。然后,我们得到一个null
的{{1}}实例。然后,我们需要将其转换为MyClass<string>
:为此,编译器将调用您的隐式运算符,但会传入null
。这会导致您的string
,因为您访问了null
,但是NullReferenceException
是x.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>
。