C# 从不使用空值?
我们目前正在经历为C#编写一些编码标准的漫长过程 我最近写了一个带有签名的方法C# 从不使用空值?,c#,null,C#,Null,我们目前正在经历为C#编写一些编码标准的漫长过程 我最近写了一个带有签名的方法 string GetUserSessionID(int UserID) 如果找不到用户的会话,则GetUserSession()返回null 在我的呼叫代码中。。。我说 string sessionID = GetUserSessionID(1) if (null == sessionID && userIsAllowedToGetSession) { session = GetNewUse
string GetUserSessionID(int UserID)
如果找不到用户的会话,则GetUserSession()返回null
在我的呼叫代码中。。。我说
string sessionID = GetUserSessionID(1)
if (null == sessionID && userIsAllowedToGetSession)
{
session = GetNewUserSession(1);
}
在最近的一次代码评审中,评审员说“您永远不应该从方法返回null,因为它会在调用方法上花费更多的工作来检查null。”
我马上喊出了诡计,好像你返回了字符串。空的话,你还得对返回的值进行某种检查
if (string.Empty == sessionID)
但是,进一步考虑一下,对于集合/数组/列表,我永远不会返回null。我将返回一个空列表
解决这个问题的方法(我认为)是将它重构为两个方法
bool SessionExists(int userID);
及
这次,GetUserSessionID将抛出SessionNotFound异常(因为它不应返回null)
现在代码看起来像
if(!SessionExists(1) && userIsAllowedToGetSession))
{
session = GetNewUserSession(1);
}
else
{
session = GetUserSessionID(1);
}
这意味着没有空值,但对我来说,这似乎有点复杂。这也是一个非常简单的例子,我想知道这将如何影响更复杂的方法
关于何时抛出异常以及如何处理异常,有很多最佳实践建议,但关于null的使用信息似乎较少
其他人是否有关于空值使用的可靠指导方针(甚至更好的标准),这对可空类型意味着什么(我们应该使用它们吗?)
提前感谢,
克里斯
=====
谢谢大家!那里有很多非常有趣的讨论。
我已经给出了egaga的答案,因为我喜欢Get vs Find作为编码指南的建议,但所有答案都很有趣。空值肯定比“魔法值”更好,也就是说,更诚实。但当发生错误时,不应返回它们——这就是例外情况。当涉及到归还收藏时。。。我同意空集合比空集合好。空表示未知/未确定 在处理数据只是“尚未确定”的数据库时,您最需要它。在您的应用程序中,对于非异常但非默认行为,NULL是一种很好的返回类型
当输出不是预期的但不足以导致异常时,使用NULL 一种可能的做法是使用get前缀作为未找到结果时抛出异常的方法,如果可能为null,则使用find前缀。因此,在客户端很容易看到代码在处理null时是否存在问题
当然,我们应该避免空值,安德烈·赫尔斯伯格(Andrej Heljsberg)在一次采访中说,如果C#现在被创建,它将有更好的方法处理空值性 保持简单。尽可能使您的类型的消费者无痛。这是一个权衡:实施的时间和获得的好处
- 在处理诸如获取列表/集合之类的事情时,按照您正确指出的那样返回一个空列表
- 类似地,对于需要返回“null”值以表示“未找到”的情况,请尝试对大量使用的类型使用。对于很少使用的类型,我想您可以接受一些null或-1(String.IndexOf)检查
如果您有更多类别,请以评论的形式发布,我将尝试解决方案。一种解决方案可能是为以下内容声明一个简单的返回类型:
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语言编码风格中去了!p> 您的合同设计答案也是我的解决方案:
if (myClass.SessionExists)
{
// Do something with myClass.Session
}
空值远比魔法值好,而且更有意义。 您还可以尝试编写一个TryGetUserSession方法。
bool TryGetUserSession(int sessionId,out session)
另外,尽量不要写null==?,因为一些开发人员发现它更难读取
亲切问候,返回null很好,以下内容简洁易懂:
var session = GetUserSessionID(1) ?? GetNewUserSession(1);
在我看来,您不应该排除使用null作为返回值。我认为这在很多情况下都是有效的。但是你应该仔细考虑每一种方法的赞成和反对。这完全取决于方法的目的和调用方可能的期望 我个人经常使用null返回值,以防您期望该方法不会返回abject(即,通过主键进行的数据库搜索可能只返回一个实例,或者不返回/null)。如果可以正确地期望方法返回值,则应使用异常
在您的特定示例中,我认为这取决于系统的上下文。例如,如果调用仅来自您可能希望有登录用户的代码,那么您应该抛出一个异常。但是,如果可能没有用户登录,因此您没有要返回的会话id,那么您应该选择返回null。我自己也担心返回null,尽管在您的示例中,这似乎是正确的做法 重要的是要清楚参数和返回值的可空性。如果您的语言无法直接表达此概念,则必须将其指定为API文档的一部分。(Java不能,我读过C#可以。)如果输入参数或返回值可以为null,请务必告诉用户在API上下文中这意味着什么 我们最大的代码库是Java应用程序,它在过去十年中稳步增长。许多内部API对其行为WRT null非常不清楚。这会导致nul癌变生长
var session = GetUserSessionID(1) ?? GetNewUserSession(1);
A.children().first().matches("Blah")
if( list != null) {
foreach( Item item in list ) {
...
}
}