15

我们有一个具有隐式字符串运算符的类型。它看起来像这样:

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',比如:

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

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

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

......但这很丑陋。

我阅读了Essential C# 5 第 4 版中的部分(关于 Safari 的“Rough Cuts”书),它说:

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

这说不要抛出异常,但这让我想知道我应该抑制异常吗?

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

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

问题解决了。但是我觉得很脏。我觉得我通过检查 null 来隐藏一个潜在的错误。我是偏执狂/肛门/愚蠢吗?

4

4 回答 4

13

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

于 2012-11-29T14:32:08.540 回答
5

我想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;
}
于 2020-02-07T07:15:03.383 回答
0

在隐式转换运算符中“抑制”异常是完全可以的。事实上,正如您所指出的,这是推荐的方法。

考虑这种情况:

Foo actualFoo = null;
string stringFoo = actualFoo;

如果编译得很好,为什么要让第二行在运行时抛出异常?那没有任何意义。

这同样适用:

string stringFoo = null;
Foo actualFoo = stringFoo;

如果您这样定义两个隐式转换运算符,则意味着您希望以与使用类型string相同的方式处理和使用类型Foo。在这种情况下,上述两种情况都是完全有效的构造(您的编译器确认)并且应该产生 null 而不是抛出异常。

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

于 2019-01-28T13:43:35.530 回答
-3

您试图将 null 转换为 Foo 类型,因为双方的类型:必须相等。

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

所以你应该使用

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

或者

string s = foo == null ? null : (string)foo;
于 2018-09-07T11:55:40.703 回答