这是一个一般性的问题(但我使用c#),最好的方法(最佳实践)是什么,对于一个有集合作为返回类型的方法,你返回null集合还是空集合?
当前回答
还有一点尚未被提及。考虑下面的代码:
public static IEnumerable<string> GetFavoriteEmoSongs()
{
yield break;
}
在调用此方法时,c#语言将返回一个空枚举数。因此,为了与语言设计(以及程序员的期望)保持一致,应该返回一个空集合。
其他回答
这取决于你的合同和具体情况。 通常最好返回空集合,但有时(很少):
Null可能意味着更具体的东西; 你的API(合约)可能会强制你返回null。
一些具体的例子:
一个UI组件(来自一个不受你控制的库),如果传递一个空集合,可能会呈现一个空表,或者如果传递null,则根本不呈现表。 在Object-to-XML (JSON/其他)中,null表示元素缺失,而空集合将呈现冗余(可能不正确)<collection /> 你正在使用或实现一个明确声明null应该返回/传递的API
在我看来,您应该返回上下文中语义正确的值,不管它是什么。“总是返回一个空集合”的规则对我来说似乎有点简单。
Suppose in, say, a system for a hospital, we have a function that is supposed to return a list of all previous hospitalizations for the past 5 years. If the customer has not been in the hospital, it makes good sense to return an empty list. But what if the customer left that part of the admittance form blank? We need a different value to distinguish "empty list" from "no answer" or "don't know". We could throw an exception, but it's not necessarily an error condition, and it doesn't necessarily drive us out of the normal program flow.
我经常对无法区分零和无答案的系统感到沮丧。我曾多次遇到这样的情况:系统要求我输入一些数字,我输入0,然后我得到一个错误消息,告诉我必须在这个字段中输入一个值。我刚刚做了:我输入了零!但它不会接受0,因为它无法区分0和no。
回复桑德斯:
Yes, I'm assuming that there's a difference between "Person didn't answer the question" and "The answer was zero." That was the point of the last paragraph of my answer. Many programs are unable to distinguish "don't know" from blank or zero, which seems to me a potentially serious flaw. For example, I was shopping for a house a year or so ago. I went to a real estate web site and there were many houses listed with an asking price of $0. Sounded pretty good to me: They're giving these houses away for free! But I'm sure the sad reality was that they just hadn't entered the price. In that case you may say, "Well, OBVIOUSLY zero means they didn't enter the price -- nobody's going to give a house away for free." But the site also listed the average asking and selling prices of houses in various towns. I can't help but wonder if the average didn't include the zeros, thus giving an incorrectly low average for some places. i.e. what is the average of $100,000; $120,000; and "don't know"? Technically the answer is "don't know". What we probably really want to see is $110,000. But what we'll probably get is $73,333, which would be completely wrong. Also, what if we had this problem on a site where users can order on-line? (Unlikely for real estate, but I'm sure you've seen it done for many other products.) Would we really want "price not specified yet" to be interpreted as "free"?
RE有两个独立的函数,一个是“有吗?”,一个是“如果有,是什么?”是的,你当然可以这么做,但你为什么要这么做呢?现在调用程序必须进行两次调用而不是一次。如果程序员没有调用“any?”而直接调用“What is it?”会发生什么?? 程序会返回一个误导的零吗?抛出异常?返回一个未定义的值?这会产生更多的代码、更多的工作和更多的潜在错误。
我看到的唯一好处是,它使您能够遵守任意规则。这条规则有什么好处,值得我们不费苦心地遵守吗?如果不是,为什么要麻烦呢?
回复Jammycakes:
考虑一下实际的代码会是什么样子。我知道问题说的是c#,但如果我写Java的话,请原谅。我的c#不是很清晰,原理是一样的。
返回null:
HospList list=patient.getHospitalizationList(patientId);
if (list==null)
{
// ... handle missing list ...
}
else
{
for (HospEntry entry : list)
// ... do whatever ...
}
具有单独的功能:
if (patient.hasHospitalizationList(patientId))
{
// ... handle missing list ...
}
else
{
HospList=patient.getHospitalizationList(patientId))
for (HospEntry entry : list)
// ... do whatever ...
}
它实际上是少了一两行代码,返回null,所以它对调用者没有更多的负担,它更少。
I don't see how it creates a DRY issue. It's not like we have to execute the call twice. If we always wanted to do the same thing when the list does not exist, maybe we could push handling down to the get-list function rather than having the caller do it, and so putting the code in the caller would be a DRY violation. But we almost surely don't want to always do the same thing. In functions where we must have the list to process, a missing list is an error that might well halt processing. But on an edit screen, we surely don't want to halt processing if they haven't entered data yet: we want to let them enter data. So handling "no list" must be done at the caller level one way or another. And whether we do that with a null return or a separate function makes no difference to the bigger principle.
Sure, if the caller doesn't check for null, the program could fail with a null-pointer exception. But if there's a separate "got any" function and the caller doesn't call that function but blindly calls the "get list" function, then what happens? If it throws an exception or otherwise fails, well, that's pretty much the same as what would happen if it returned null and didn't check for it. If it returns an empty list, that's just wrong. You're failing to distinguish between "I have a list with zero elements" and "I don't have a list". It's like returning zero for the price when the user didn't enter any price: it's just wrong.
我看不出向集合附加附加属性有什么帮助。打电话的人仍然需要检查。这比检查null好吗?同样,最糟糕的情况是程序员忘记检查,并给出不正确的结果。
A function that returns null is not a surprise if the programmer is familiar with the concept of null meaning "don't have a value", which I think any competent programmer should have heard of, whether he thinks it's a good idea or not. I think having a separate function is more of a "surprise" problem. If a programmer is unfamiliar with the API, when he runs a test with no data he'll quickly discover that sometimes he gets back a null. But how would he discover the existence of another function unless it occurred to him that there might be such a function and he checks the documentation, and the documentation is complete and comprehensible? I would much rather have one function that always gives me a meaningful response, rather than two functions that I have to know and remember to call both.
返回null可能更有效,因为不会创建新的对象。然而,它也经常需要一个空检查(或异常处理)。
从语义上讲,null和空列表的意思是不同的。这些差异是微妙的,在特定的情况下,一种选择可能比另一种更好。
不管你的选择是什么,记录下来以避免混淆。
框架设计指引第二版(第256页):
不返回空值从 集合属性或方法 返回集合。返回空 集合或空数组。
这是另一篇关于不返回null的好处的有趣文章(我试图在Brad Abram的博客上找到一些东西,他链接到了这篇文章)。
编辑-正如Eric Lippert现在对原始问题的评论,我也想链接到他的优秀文章。
我认为null与空集合不同,您应该选择哪一个最能代表您要返回的内容。在大多数情况下,null什么都不是(SQL除外)。空的收藏是一种东西,尽管是一种空的东西。
如果你不得不选择一个或另一个,我会说你应该倾向于一个空集合而不是null。但有时空集合与空值并不相同。
推荐文章
- 虚拟方法和抽象方法的区别
- i++和++i的区别是什么?
- 可空对象必须有一个值
- 按类型查找WPF窗口中的所有控件
- 为什么我不能继承静态类?
- 为什么java.util.Set没有get(int index)?
- 如何在c#中获取CPU的使用情况?
- BindingFlags。IgnoreCase不为Type.GetProperty()工作?
- 使用私有静态方法的优点
- 一个任务被取消了?
- 新DateTime()与默认值(DateTime)
- 从Description属性中获取Enum
- 从包含文件名的路径获取不包含文件名的完整路径
- 如何从字符串的开始或结束删除所有空白?
- 为什么使用try {} finally{}和一个空的try块?