通用类型和 ?: 运算符不起作用
Generic type and ?: operator doesn't work
任何人都可以解释为什么这段代码在使用 ?
运算符时失败但与 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;
然后你就陷入了我之前描述的同样的情况,因为你从来没有创建一个空的 MyClass<string>
,所以你永远不会尝试转换这个 null
MyClass<string>
变成 string
.
任何人都可以解释为什么这段代码在使用 ?
运算符时失败但与 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;
然后你就陷入了我之前描述的同样的情况,因为你从来没有创建一个空的 MyClass<string>
,所以你永远不会尝试转换这个 null
MyClass<string>
变成 string
.