C# 隐式运算符应该处理null吗?
我们有一个类型,它有一个隐式字符串运算符。看起来是这样的:C# 隐式运算符应该处理null吗?,c#,exception,implicit-conversion,C#,Exception,Implicit Conversion,我们有一个类型,它有一个隐式字符串运算符。看起来是这样的: public class Foo { readonly string _value; Foo(string value) { _value = value; } public static implicit operator string(Foo foo) { return foo._value; } public static imp
public class Foo
{
readonly string _value;
Foo(string value)
{
_value = value;
}
public static implicit operator string(Foo foo)
{
return foo._value;
}
public static implicit operator Foo(string fooAsText)
{
return new Foo(fooAsText);
}
}
我们刚刚遇到了一个场景,传递给隐式操作符的实例是null
。显然,我们最终得到了一个NullReferenceException
我认为这很公平,毕竟,一个类型的字符串表示形式是空的-很难说-所以异常似乎是有效的,我们不应该拦截/抑制/处理/忽略。我的推理是“有人给了我一个空值,我为什么要返回空值?”。我在其他方法中不这样做。我想,‘我知道,在转换它之前,我只需要检查null’,类似于:
字符串s=foo==null?null:foo代码>
但这不起作用,因为它现在在比较为null之前转换为字符串。当然,这种比较是可行的:
Foo f = null;
string s;
if (f != null)
{
s = f;
}
。。。但那太难看了
我在(一本关于狩猎的“粗略剪裁”书)中读到了这一部分,它说:
不要从隐式转换中抛出异常
这说明不要抛出异常,但它让我想知道我应该抑制异常吗
最明显的做法是跳入该方法并将其更改为:
public static implicit operator string(Foo foo)
{
return foo == null ? null : foo._value;
}
问题解决了。但是我觉得很脏。我感觉通过检查null来隐藏潜在的bug。我是偏执狂/肛门病/愚蠢吗 在这种情况下,我建议可能失败的运算符应该是显式的,而不是隐式的。隐式转换的思想是它正在扩大(即它永远不会失败)。另一方面,显式转换有时会失败。您试图将null强制转换为Foo类型,因为
:
两侧的类型必须相等
string s = foo == null ? null : foo;
所以你应该使用
string s = foo == null ? (string)null : foo;
或
在隐式转换运算符中“suppress”异常是完全正确的。事实上,正如您所指出的,这是推荐的方法
考虑以下情况:
Foo actualFoo = null;
string stringFoo = actualFoo;
如果编译得很好,为什么要让第二行在运行时抛出异常?那毫无意义
这同样适用于:
string stringFoo = null;
Foo actualFoo = stringFoo;
如果这样定义两个隐式转换运算符,则意味着您希望以与使用typestring相同的方式处理和使用typeFoo。在这种情况下,上述两种情况都是完全有效的构造(您的编译器确认了这一点),应该生成null而不是抛出异常
现在,正如Dan指出的,如果这不是您想要的,那么您需要定义一个显式转换。我希望
Foo
与string
的行为相同。所以,我希望
Foo-Foo=null;
等于(null,foo);
是真的
Equals将尝试将foo
强制转换为字符串,以便调用隐式运算符。空值foo
应该公开与空值字符串
相同的值,即null
因此,如果您确实希望有一个隐式运算符,我会将其实现为:
公共静态隐式运算符字符串(Foo-Foo)
{
返回foo?\u值;
}
这一切都取决于您的用例。你想让字符串
为空吗?很好。理想情况下,我们希望永远不会遇到Foo
的空实例。六羟甲基三聚氰胺六甲醚。。。也许它应该是一个struct…@SteveDunn:一件重要的事情是:NullReferenceException
总是表示代码中引发异常的bug,而不是调用代码。因此,简单地不检查foo
是否为null
是运算符中的一个错误。这也是文档建议的:
string stringFoo = null;
Foo actualFoo = stringFoo;