这是一个一般性的问题(但我使用c#),最好的方法(最佳实践)是什么,对于一个有集合作为返回类型的方法,你返回null集合还是空集合?
当前回答
我喜欢在这里用适当的例子来解释。
考虑一个案例。
int totalValue = MySession.ListCustomerAccounts()
.FindAll(ac => ac.AccountHead.AccountHeadID
== accountHead.AccountHeadID)
.Sum(account => account.AccountValue);
这里考虑我使用的函数..
1. ListCustomerAccounts() // User Defined
2. FindAll() // Pre-defined Library Function
我可以很容易地使用ListCustomerAccount和FindAll代替。
int totalValue = 0;
List<CustomerAccounts> custAccounts = ListCustomerAccounts();
if(custAccounts !=null ){
List<CustomerAccounts> custAccountsFiltered =
custAccounts.FindAll(ac => ac.AccountHead.AccountHeadID
== accountHead.AccountHeadID );
if(custAccountsFiltered != null)
totalValue = custAccountsFiltered.Sum(account =>
account.AccountValue).ToString();
}
注意:由于AccountValue不为空,Sum()函数不会为空 返回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.
框架设计指引第二版(第256页):
不返回空值从 集合属性或方法 返回集合。返回空 集合或空数组。
这是另一篇关于不返回null的好处的有趣文章(我试图在Brad Abram的博客上找到一些东西,他链接到了这篇文章)。
编辑-正如Eric Lippert现在对原始问题的评论,我也想链接到他的优秀文章。
空集合。总是这样。
这糟透了:
if(myInstance.CollectionProperty != null)
{
foreach(var item in myInstance.CollectionProperty)
/* arrgh */
}
在返回集合或枚举对象时,NEVER返回null被认为是最佳实践。ALWAYS返回一个空的可枚举/集合。它可以防止前面提到的废话,并防止你的车被同事和你的类的用户怂恿。
在谈论属性时,总是设置一次属性,然后忘记它
public List<Foo> Foos {public get; private set;}
public Bar() { Foos = new List<Foo>(); }
在.NET 4.6.1中,你可以将这些内容进行大量压缩:
public List<Foo> Foos { get; } = new List<Foo>();
当谈论返回枚举对象的方法时,你可以很容易地返回一个空的枚举对象而不是null…
public IEnumerable<Foo> GetMyFoos()
{
return InnerGetFoos() ?? Enumerable.Empty<Foo>();
}
使用Enumerable.Empty<T>()可以被视为比返回一个新的空集合或数组更有效。
如果一个空集合在语义上是有意义的,那就是我喜欢返回的。为GetMessagesInMyInbox()返回一个空集合表示“您的收件箱中确实没有任何消息”,而返回null可能用于表示可用数据不足,无法说明可能返回的列表应该是什么样子。
Go似乎是首选nil而不是空数组的一种语言。
https://github.com/golang/go/wiki/CodeReviewComments#declaring-empty-slices
当声明一个空切片时,优先使用var t []string而不是t:= []string{}。前者声明一个nil切片值,而后者非nil但长度为0。它们在功能上是等价的——它们的len和cap都是0——但是nil片是首选样式。
推荐文章
- 虚拟方法和抽象方法的区别
- i++和++i的区别是什么?
- 可空对象必须有一个值
- 按类型查找WPF窗口中的所有控件
- 为什么我不能继承静态类?
- 为什么java.util.Set没有get(int index)?
- 如何在c#中获取CPU的使用情况?
- BindingFlags。IgnoreCase不为Type.GetProperty()工作?
- 使用私有静态方法的优点
- 一个任务被取消了?
- 新DateTime()与默认值(DateTime)
- 从Description属性中获取Enum
- 从包含文件名的路径获取不包含文件名的完整路径
- 如何从字符串的开始或结束删除所有空白?
- 为什么使用try {} finally{}和一个空的try块?