永远不要使用Nulls?

时间:2009-05-14 09:33:25

标签: c# null

我们目前正在经历为C#编写一些编码标准的漫长过程。

我最近用签名

写了一个方法
string GetUserSessionID(int UserID)

如果没有为用户找到会话,GetUserSession()将返回null。

在我的通话代码中......我说......

string sessionID = GetUserSessionID(1)
if (null == sessionID && userIsAllowedToGetSession)
{
    session = GetNewUserSession(1);
}

在最近的一次代码审查中,审阅者说“你永远不应该从方法中返回null,因为它会在调用方法上调查空值。”

我立刻哭了恶作剧,好像你回来了。很多时候你还要对返回的值进行某种检查。

if (string.Empty == sessionID)

然而,考虑到这一点,我不会在Collection / Array / List的情况下返回null。我会返回一个空列表。

对此的解决方案(我认为)将重构为2种方法。

bool SessionExists(int userID);

string GetUserSessionID(int UserID);

这一次,GetUserSessionID会抛出一个SessionNotFound异常(因为它不应该返回null)

现在代码看起来像......

if(!SessionExists(1) && userIsAllowedToGetSession))
{
   session = GetNewUserSession(1);
}
else
{
   session = GetUserSessionID(1);
}

现在这意味着没有空值,但对我来说这似乎有点复杂。这也是一个非常简单的例子,我想知道这将如何影响更复杂的方法。

关于何时抛出异常以及如何处理异常,有很多关于最佳做法的建议,但似乎关于使用null的信息较少。

是否有其他人对空值的使用有任何可靠的指导(甚至更好的标准),这对于可空类型意味着什么(我们应该使用它们吗?)

提前致谢,

克里斯。

=====

谢谢大家!那里有很多有趣的讨论。

我已经给了egaga的答案,因为我喜欢将Get vs Find作为编码指南的建议,但所有这些都是有趣的答案。

15 个答案:

答案 0 :(得分:29)

nulls肯定比“神奇的价值”更好,即更诚实。但是在发生错误时不应该返回它们 - 这就是例外情况。当谈到返回集合时......我更赞同空集合而不是null,我同意。

答案 1 :(得分:11)

返回null很好,以下内容简洁易懂:

var session = GetUserSessionID(1) ?? GetNewUserSession(1);

答案 2 :(得分:8)

可能的做法是对未在找到结果时抛出异常的方法使用 get 前缀,如果可能为null,则使用 find 前缀。因此,在客户端很容易看到代码是否在处理null时遇到问题。

当然应该避免空值,Andrej Heljsberg在接受采访时说,如果现在创建C#,它将有更好的方法来处理可空性。 http://www.computerworld.com.au/article/261958/-z_programming_languages_c?pp=3&fp=&fpid=

答案 3 :(得分:5)

在我看来,你不应该排除使用null作为返回值。我认为它在许多情况下都是有效的。但是你应该仔细考虑每种方法的专业人士和骗子。这完全取决于方法的目的和呼叫者的期望。

在您可能期望该方法不返回abject(即主键的数据库搜索,可能只返回一个实例或none / null)的情况下,我个人非常使用null返回值。当您可以正确地期望方法返回值时,您应该使用异常。

在您的特定示例中,我认为这取决于系统的上下文。如果实例的调用仅来自您可能期望登录用户的代码,则应该抛出异常。但是,如果没有用户登录,因此您没有要返回的会话ID,则应选择返回null。

答案 4 :(得分:5)

为什么不使用Null design pattern

答案 5 :(得分:4)

保持简单。让您的类型的消费者尽可能轻松。这是一个权衡:实施的时间和获得的好处。

  • 在处理提取列表/集合之类的事情时,请正确指出返回空列表。
  • 同样,对于需要返回“null”值以表示“未找到”的情况,请尝试将Null Object pattern用于使用频繁的类型。对于很少使用的类型,我猜你可以使用几个检查null或-1(String.IndexOf)。

如果您有更多类别,请发表评论,我会尝试解决方案。

答案 6 :(得分:3)

Nulls远比神奇的价值更好,更有意义。 您也可以尝试编写TryGetUserSession方法。

bool TryGetUserSession(int sessionId, out session)

还尝试不写nulls == ???,因为一些开发人员发现它更难阅读。

亲切的问候,

答案 7 :(得分:3)

我很担心自己会返回空值,但在你的例子中,这似乎是正确的做法。

重要的是清楚关于参数和返回值的可空性。如果您的语言无法直接表达此概念,则必须将 指定为API文档的一部分。 (Java不能,我已经读过C#可以。)如果输入参数或返回值 可以为null,请务必告诉用户中的意味着什么您的API的上下文。

我们最大的代码库是一个Java应用程序,在过去十年中稳步增长。许多内部API都非常不清楚他们的行为WRT null。由于每个人都在进行防御性编程,这导致了无处不在的空检的恶性增长。

特别难看:返回集合的函数返回null而不是空集合。 WTF!?不要那样做!

在字符串的情况下,请务必区分必须存在的字符串,但可以为空,并且字符串是真正可选的(可以为null)。在使用XML时,我们经常遇到这种区别:强制性的元素,但可以是空的,而不是可选的元素。

该系统的一部分提供了用于实现业务规则的类XML结构的查询,它非常激进地实现了无空闲。它到处使用Null对象模式。在这种情况下,这很有用,因为它允许你做以下事情:

A.children().first().matches("Blah")

如果A的第一个孩子被命名为“Blah”,那么这个表达式应该返回true。如果A没有子节点,它不会崩溃,因为在这种情况下,first()返回一个实现Node接口的NullNode,但从不“匹配”任何东西。

总结:

  • 明确了API中null的含义和允许性。
  • 使用你的大脑。
  • 不要教条。

答案 8 :(得分:2)

一种解决方案可能是为这些事情声明一个简单的返回类型:

class Session
{
    public bool   Exists;
    public string ID;
}

Session GetUserSession(int userID) {...}

...

Session session = GetUserSessionID(1);

if (session.Exists)
{
    ... use session.ID
}

我一般都喜欢避免空值,但字符串有点特殊。我经常最终调用string.IsNullOrEmpty()。这么多,我们使用字符串的扩展方法:

static class StringExtensions
{
    public static bool IsNullOrEmpty(this string value)
    {
        return string.IsNullOrEmpty(value);
    }
}

然后你可以这样做:

string s = ... something

if (s.IsNullOrEmpty())
{
 ...
}

此外,由于我们的主题是编码风格:

什么是不自然的“if(null == ...)”风格?这对于C#来说是完全不必要的 - 看起来有人带来了C#编码风格的一些C ++包袱!

答案 9 :(得分:2)

我更喜欢返回空集合而不是空值,因为这有助于避免使调用者代码混乱,如下所示:

if( list != null) {
    foreach( Item item in list ) {
         ...
    }
}

答案 10 :(得分:1)

按合同回答的设计也是我的解决方案:

if (myClass.SessionExists)
{
   // Do something with myClass.Session
}

答案 11 :(得分:1)

我们总是返回空列表/集合,并且不返回NULL列表/集合,因为处理空集合/列表减少了调用函数的负担。

Nullable - 当你想避免处理数据库中的“null”值时,nullables特别有用。您可以简单地将GetDefaultOrValue用于任何Nullable类型,而无需担心业务对象中的数据库值为null。我们通常只在我们的业务对象中定义Nullables,并且我们真正想要转义db null值检查等等。

答案 12 :(得分:1)

nulls的发明者认为这是个坏主意。

请参阅:http://lambda-the-ultimate.org/node/3186

答案 13 :(得分:1)

我有一个类似的问题,虽然我通过一个例外并被告知我应该返回null,

我们最终阅读了

this blog post about vexing exceptions

我建议您阅读。

答案 14 :(得分:0)

NULL表示未知/未确定。

在使用数据库时,您最需要它,而数据库中的数据“尚未确定”。在您的应用程序中,NULL是非异常但非默认行为的良好返回类型。

当输出不是预期但对于异常而言不够严重时,使用NULL。