这是一个一般性的问题(但我使用c#),最好的方法(最佳实践)是什么,对于一个有集合作为返回类型的方法,你返回null集合还是空集合?


当前回答

视情况而定。如果是特殊情况,则返回null。如果函数恰好返回一个空集合,那么返回显然是可以的。但是,由于无效参数或其他原因而返回一个空集合作为特殊情况并不是一个好主意,因为它掩盖了一个特殊情况条件。

实际上,在这种情况下,我通常更喜欢抛出一个异常,以确保它真的没有被忽略:)

说它使代码更健壮(通过返回一个空集合),因为它们不必处理null条件是不好的,因为它只是掩盖了应该由调用代码处理的问题。

其他回答

如果一个空集合在语义上是有意义的,那就是我喜欢返回的。为GetMessagesInMyInbox()返回一个空集合表示“您的收件箱中确实没有任何消息”,而返回null可能用于表示可用数据不足,无法说明可能返回的列表应该是什么样子。

有人可能会说,空对象模式背后的原因与支持返回空集合的原因类似。

在我看来,您应该返回上下文中语义正确的值,不管它是什么。“总是返回一个空集合”的规则对我来说似乎有点简单。

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和空列表的意思是不同的。这些差异是微妙的,在特定的情况下,一种选择可能比另一种更好。

不管你的选择是什么,记录下来以避免混淆。

空的对消费者更友好。

有一个明确的方法来创建一个空的枚举:

Enumerable.Empty<Element>()