Enumerable.Any<T>(this IEnumerable<T> source) should handle null enumerable too, surely?
Is there some pedantic Enumerator-theory-based reason why the Any() method throws an ArgumentNullException
for a null enumerable?
I use IEnumerable wherever possible to pass collections of data around - but in most cases I then have this kind of code:
public class Foo
{
public IEnumerable<IBar> Bars { get; set; }
}
////----
public static void UseAFoo(Foo foo)
{
//if Bars has something in it, then do something:
if(foo.Bars != null && foo.Bars.Any())
{
//blah
}
}
Or,
if((foo.Bars ?? Enumerable.Empty<IBar>()).Any())
{
//ugh!
}
Or modify the property declaration thus:
public class Foo
{
private IEnumerable<IBar> _bars;
public IEnumerable<IBar> Bars
{
get { return _bars ?? Enumerab开发者_JAVA百科le.Empty<IBar>(); }
set { _bars = value; }
}
}
Or the 'more efficient' way:
get { return _bars; }
set { _bars = value ?? Enumerable.Empty<IBar>(); }
In every case - it's nasty. Okay so I can do my own extension method (which I have) - but naming is a bit tricky, because the best name is already taken! I've gone for NotNullAndAny()
but I don't like it.
Any()
(and it's delegate-driven brother) should, in my opinion, return false if the Enumerable is null - it should not throw an ArgumentNullException
.
But then like I say at the start - is there some hidden contract here that I'm missing? Or is it just pedantry ;)
UPDATE
I had a feeling that the consensus was going to be that all linq extensions should throw ArgumentNullException
, even the case of Any()
- and to be honest while I feel that the case can still be made for Any()
, the arguments for are not persuasive enough to overcome the basic fact that if an enumerable is null, no general operation can be completed satisfactorily for it and therefore an exception has to be thrown.
Thus I will go with an extra extension method NotNullAndAny()
to clean up my code where nulls are reasonably possible (and not an error). In cases where a null enumerable is not allowed I already throw ArgumentNullException
too. In some cases however it's more practical to allow consumers of my code to leave a property unset whilst equally not forcing my classes to require manually implemented properties or default constructors to make sure these properties don't ever get a null
. If that's my choice, then I consign my own code to have to check both null and empty.
Only thing now is which response to mark as the answer! :)
I can't answer whether there's a sound theoretical reason for it - but to me, we are dealing with two distinct concepts. I'll misuse language and talk about lists, rather than enums, but the same arguments should apply: There is a big difference between there being a list which contains no items, and the list not being present at all.
And personally, given your listed code options, I'd go with one you didn't list (if it makes sense to have a settable enumerable, and your class really can work with any enumerable):
public class Foo
{
private IEnumerable<IBar> _bars = Enumerable.Empty<IBar>();;
public IEnumerable<IBar> Bars
{
get { return _bars; }
set {
if(value==null) throw new ArgumentNullException("value");
_bars = value;
}
}
}
i.e. Don't let nulls creep into your design if you don't want to deal with them
I think it should not return false
when parameter is null
.
With this one throwing an exception for a null
parameter matches up with general behavior of other BCL
classes.
It does return false
when the sequence
is empty
.
There is a difference between having a null
value and having a parameter value as an empty sequence
(which is a sequence with no elements in it).
Null in practice is often an incorrect state and is treated as such by the vast majority of APIs - the API for linq is following this. Perhaps you should question why you have null enumerables in the first place, and guard against this. A second approach would be to write your own extension methods that give you the desired behaviour. Excessive null checking (inside code rather than just parameter checking) is usually a code smell.
精彩评论