从函数返回数据的最佳实践是什么?是返回Null对象好还是返回空对象好?为什么要选择一种而不是另一种呢?
考虑一下:
public UserEntity GetUserById(Guid userId)
{
//Imagine some code here to access database.....
//Check if data was returned and return a null if none found
if (!DataExists)
return null;
//Should I be doing this here instead?
//return new UserEntity();
else
return existingUserEntity;
}
让我们假设在这个程序中存在有效的情况,即数据库中没有具有该GUID的用户信息。我认为在这种情况下抛出异常是不合适的??另外,我的印象是异常处理会损害性能。
我们使用CSLA。NET,并且它认为失败的数据获取应该返回一个“空”对象。这实际上是相当烦人的,因为它要求检查obj。IsNew而不是obj == null。
正如前面提到的,null返回值将导致代码立即失败,从而降低了由空对象引起的隐形问题的可能性。
就我个人而言,我认为null更优雅。
这是一种非常常见的情况,我很惊讶这里的人似乎对此感到惊讶:在任何web应用程序中,数据通常是使用querystring参数获取的,这显然会被破坏,因此要求开发人员处理“未找到”的情况。
你可以这样处理:
if (User.Exists(id)) {
this.User = User.Fetch(id);
} else {
Response.Redirect("~/notfound.aspx");
}
...但是这每次都是对数据库的额外调用,这在高流量页面上可能是一个问题。而:
this.User = User.Fetch(id);
if (this.User == null) {
Response.Redirect("~/notfound.aspx");
}
...只需要一个呼叫。
这取决于什么对你的案子最有意义。
返回null是否有意义?“不存在这样的用户”?
或者创建一个默认用户有意义吗?当您可以安全地假设如果用户不存在,则调用代码在请求时希望用户存在时,这是最有意义的。
或者,如果调用代码要求使用无效ID的用户,抛出异常(如“FileNotFound”)是否有意义?
然而,从分离关注点/SRP的角度来看,前两点更为正确。从技术上讲,第一个是最正确的(但只差一点点)——GetUserById应该只负责一件事——获取用户。通过返回其他内容来处理自己的“用户不存在”情况可能违反SRP。如果您确实选择抛出异常,则分隔为不同的check - bool DoesUserExist(id)是合适的。
根据下面大量的评论:如果这是一个api级别的设计问题,这个方法可以类似于“OpenFile”或“readwholfile”。我们正在从某个存储库中“打开”一个用户,并从结果数据中补充对象。在这种情况下,一个例外可能是合适的。也许不是,但也有可能。
所有的方法都是可以接受的——这取决于API/应用程序的上下文。
更多的肉要磨:让我们说我的DAL返回一个NULL的GetPersonByID,正如一些建议。我的(相当薄)BLL应该做什么,如果它收到一个NULL?传递NULL,并让最终消费者担心它(在这种情况下,一个ASP。网络页面)?让BLL抛出一个异常怎么样?
BLL可能正在被ASP使用。Net和Win App,或者其他类库——我认为期望最终消费者本质上“知道”GetPersonByID方法返回null是不公平的(除非使用空类型,我猜)。
My take (for what it's worth) is that my DAL returns NULL if nothing is found. FOR SOME OBJECTS, that's ok - it could be a 0:many list of things, so not having any things is fine (e.g. a list of favourite books). In this case, my BLL returns an empty list. For most single entity things (e.g. user, account, invoice) if I don't have one, then that's definitely a problem and a throw a costly exception. However, seeing as retrieving a user by a unique identifier that's been previously given by the application should always return a user, the exception is a "proper" exception, as in it's exceptional. The end consumer of the BLL (ASP.Net, f'rinstance) only ever expects things to be hunky-dory, so an Unhandled Exception Handler will be used instead of wrapping every single call to GetPersonByID in a try - catch block.
如果我的方法有明显的问题,请让我知道,因为我总是渴望学习。正如其他帖子所说,异常是代价高昂的事情,“先检查”的方法是好的,但异常应该只是例外。
我很喜欢这篇文章,很多关于“视情况而定”的好建议:-)