定义两个可为 null 的隐式运算符时无法将 null 转换为 struct
Cannot convert null to struct when defining two nullable implicit operators
以下不编译:
public struct Foo
{
public static implicit operator Foo(string bar)
{
return new Foo();
}
public static implicit operator Foo(long? bar)
{
return new Foo();
}
public static void Test()
{
Foo bar = 0;
Foo bar2 = (long?)null;
Foo bar3 = "";
Foo bar4 = null; // Cannot convert null to 'Foo' because it is a non-nullable value type
}
}
'Foo bar4 = null' 失败,大概是因为编译器不知道使用哪个隐式运算符,因为从 long 更改运算符?太长导致该行编译但 'Foo bar2 = (long?)null' 反而失败(需要显式转换)。
我的问题是;有没有办法让 'Foo bar4 = null' 也能工作,或者这只是语言的限制(我不能添加 'null' 运算符或告诉它哪个用于 null 例如)?
我知道我可以将结构更改为 class,但我不希望它为 null,我希望能够让 null 创建它的一个实例。
编辑: 我应该补充一点,我知道有很多方法可以解决这个问题,但是因为'= null'(本质上是'new Foo()')有效只有一个隐式运算符,我只是想知道是否有可能让它仍然与它们一起工作(我觉得语言中应该有一种方法可以做到这一点 - 现在或将来,不?).
您的结构不可为空,因为您引入了一个可以将空值转换为该类型的转换。演员表本身只是一个不改变类型的成员语义。
事实上 struct
本身是 never null,但是对它的引用 may 是,但只有当它们属于 Nullable<Foo>
类型。所以 bar4
需要是 Foo?
类型,这与 Nullable<Foo>
.
相同
如果我没记错的话,结构永远不能被赋值为 null,因为它是一个值类型,类似于 int
、bool
和 DateTime
。
但是,您可以像这样使用 Nullable:
Foo? bar4 = null;
或
Nullable<Foo> bar4 = null;
确保像对待任何其他 Nullable 一样对待它并在引用 bar4.Value
之前检查 .HasValue
以避免美妙的 NullReferenceException。
My question is; Is there a way to make 'Foo bar4 = null' work as well, or is this just a limitation of the language (that I cannot add a 'null' operator or tell it which one to use for null for instance)?
根据这个问题和你的编辑,你基本上是在问
Why does Foo bar4 = null
compile when it does not if I add another implicit cast operator?
答案很简单。 null
没有任何上下文是无类型的,因此编译器不知道要使用哪个运算符。为什么?好吧,支持该语言的重载解析算法不会检查您尝试将 null
分配给的事物的类型,因此它不知道您想要哪个运算符。
您可能会争辩说可以修改未来的语言规范来进行这种额外的分析,但团队可能认为这不值得付出努力,否则这将是一个重大变化。
你能做的最好的事情就是避免在这种情况下进行转换。根据您的 C# 水平,您可以执行以下任一操作:
Foo bar4 = default;
Foo bar4 = default(Foo);
这导致可用 Foo
。两个默认表达式和 new Foo()
都是等价的。它们都会产生一个结构,其所有字段都被清零。
有关详细信息,请参阅 C# 编程指南的 default value expressions 部分。
最后,虽然您可以使用将 null
转换为结构的单个隐式转换运算符,但这并不意味着您 应该 。阅读该代码但不知道演员表的人可能会质疑他们的理智几分钟。如果可以,最好不要偏离惯用代码。
以下不编译:
public struct Foo
{
public static implicit operator Foo(string bar)
{
return new Foo();
}
public static implicit operator Foo(long? bar)
{
return new Foo();
}
public static void Test()
{
Foo bar = 0;
Foo bar2 = (long?)null;
Foo bar3 = "";
Foo bar4 = null; // Cannot convert null to 'Foo' because it is a non-nullable value type
}
}
'Foo bar4 = null' 失败,大概是因为编译器不知道使用哪个隐式运算符,因为从 long 更改运算符?太长导致该行编译但 'Foo bar2 = (long?)null' 反而失败(需要显式转换)。
我的问题是;有没有办法让 'Foo bar4 = null' 也能工作,或者这只是语言的限制(我不能添加 'null' 运算符或告诉它哪个用于 null 例如)?
我知道我可以将结构更改为 class,但我不希望它为 null,我希望能够让 null 创建它的一个实例。
编辑: 我应该补充一点,我知道有很多方法可以解决这个问题,但是因为'= null'(本质上是'new Foo()')有效只有一个隐式运算符,我只是想知道是否有可能让它仍然与它们一起工作(我觉得语言中应该有一种方法可以做到这一点 - 现在或将来,不?).
您的结构不可为空,因为您引入了一个可以将空值转换为该类型的转换。演员表本身只是一个不改变类型的成员语义。
事实上 struct
本身是 never null,但是对它的引用 may 是,但只有当它们属于 Nullable<Foo>
类型。所以 bar4
需要是 Foo?
类型,这与 Nullable<Foo>
.
如果我没记错的话,结构永远不能被赋值为 null,因为它是一个值类型,类似于 int
、bool
和 DateTime
。
但是,您可以像这样使用 Nullable
Foo? bar4 = null;
或
Nullable<Foo> bar4 = null;
确保像对待任何其他 Nullablebar4.Value
之前检查 .HasValue
以避免美妙的 NullReferenceException。
My question is; Is there a way to make 'Foo bar4 = null' work as well, or is this just a limitation of the language (that I cannot add a 'null' operator or tell it which one to use for null for instance)?
根据这个问题和你的编辑,你基本上是在问
Why does
Foo bar4 = null
compile when it does not if I add another implicit cast operator?
答案很简单。 null
没有任何上下文是无类型的,因此编译器不知道要使用哪个运算符。为什么?好吧,支持该语言的重载解析算法不会检查您尝试将 null
分配给的事物的类型,因此它不知道您想要哪个运算符。
您可能会争辩说可以修改未来的语言规范来进行这种额外的分析,但团队可能认为这不值得付出努力,否则这将是一个重大变化。
你能做的最好的事情就是避免在这种情况下进行转换。根据您的 C# 水平,您可以执行以下任一操作:
Foo bar4 = default;
Foo bar4 = default(Foo);
这导致可用 Foo
。两个默认表达式和 new Foo()
都是等价的。它们都会产生一个结构,其所有字段都被清零。
有关详细信息,请参阅 C# 编程指南的 default value expressions 部分。
最后,虽然您可以使用将 null
转换为结构的单个隐式转换运算符,但这并不意味着您 应该 。阅读该代码但不知道演员表的人可能会质疑他们的理智几分钟。如果可以,最好不要偏离惯用代码。