隐式运算符应该处理null吗?

时间:2012-11-29 14:29:05

标签: c# exception-handling 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 implicit operator Foo(string fooAsText)
    {
        return new Foo(fooAsText);
    }

}

我们只有一个场景,传递给隐式运算符的实例是null 。显然,我们最终得到了NullReferenceException

我认为这是公平的,毕竟,什么是一个null的类型的字符串表示 - 很难说 - 所以异常似乎是有效的,我们不应该拦截/抑制/处理/忽略。我的理由是,有人给我一个null,为什么我应该返回null。我不会用其他方法做到这一点'。我想,“我知道,我只是在转换它之前检查null”,如下所示:

string s = foo == null ? null : foo;

但这不起作用,因为它现在转换为字符串之前 比较为null。当然,这种比较可行:

Foo f = null;
string s;
if (f != null)
{
    s = f;
}

......但那只是丑陋。

我阅读了Essential C# 5 4th edition(a' Rough Cuts' Safari上的书)中的部分,并说:

  

不要从隐式转换中抛出异常。

这表示不会抛出异常,但是如果我压制异常会让我感到疑惑?

最明显的做法是跳转到方法并将其更改为:

public static implicit operator string(Foo foo)
{
    return foo == null ? null : foo._value;
}

问题解决了。但我觉得很脏。我觉得我通过检查null来隐藏潜在的bug。我是偏执狂/肛门/傻瓜吗?

4 个答案:

答案 0 :(得分:11)

在这种情况下我建议的是,失败的运算符应该是显式的而不是隐式的。隐式转换的想法是它正在扩大(即它永远不会失败。)另一方面,明确的转换被理解为有时会失败。

答案 1 :(得分:2)

我希望Foo的行为与string相同。所以,我希望

Foo foo = null;
string.Equals(null, foo);

是真的。

string.Equals将尝试将foo转换为字符串,以便调用隐式运算符。空值foo应该与空值string暴露相同的值,即null

因此,如果您确实希望有一个隐式运算符,则可以将其实现为:

public static implicit operator string(Foo foo)
{
    return foo?._value;
}

答案 2 :(得分:-1)

您正在尝试将Foo类型强制为null,因为:两侧的类型必须相等。

string s = foo == null ? null : foo;

所以您应该使用

string s = foo == null ? (string)null : foo;

string s = foo == null ? null : (string)foo;

答案 3 :(得分:-1)

最好在隐式转换运算符内“抑制”异常。实际上,正如您所指出的那样,这是推荐的方法。

考虑这种情况:

Foo actualFoo = null;
string stringFoo = actualFoo;

如果此编译很好,为什么还要让第二行在运行时引发异常?那会很有意义。

同样如此:

string stringFoo = null;
Foo actualFoo = stringFoo;

如果您要同时定义两个隐式转换运算符,则意味着您要像对待 string 一样对待和使用 Foo 类型。在这种情况下,以上两种情况都是完全有效的构造(您的编译器已确认),并且应产生null而不是引发异常。

现在,如Dan所指出的那样,如果这不是您想要的,那么您将需要定义一个显式转换。