I don't. I do .Where()
evens.Where(n => n > 10); // returns empty collection
evens.Where(n => n > 10).First(); // throws exception
evens.Where(n => n > 10).FirstOrDefault(); // returns 0
The first case just returns a collection, so I can simply check if the count is greater than 0 to know if there are any matches.
When using the second, I wrap in a try/catch block that handles InvalidOperationException specfically to handle the case of an empty collection, and just rethrow (bubble) all other exceptions. This is the one I use the least, simply because I don't like writing try/catch statements if I can avoid it.
In the third case I'm OK with the code returning the default value (0) when no match exists - after all, I did explicitly say "get me the first or default" value. Thus, I can read the code and understand why it happens if I ever have a problem with it.
Update:
For .NET 2.0 users, I would not recommend the hack that has been suggested in comments. It violates the license agreement for .NET, and it will in no way be supported by anyone.
Instead, I see two ways to go:
Upgrade. Most of the stuff that runs on 2.0 will run (more or less) unchanged on 3.5. And there is so much in 3.5 (not just LINQ) that is really worth the effort of upgrading to have it available. Since there is a new CLR runtime version for 4.0, there are more breaking changes between 2.0 and 4.0 than between 2.0 and 3.5, but if possible I'd recommend upgrading all the way to 4.0. There's really no good reason to be sitting around writing new code in a version of a framework that has had 3 major releases (yes, I count both 3.0, 3.5 and 4.0 as major...) since the one you're using.
Find a work-around to the Find
problem. I'd recommend either just using FindIndex
as you do, since the -1 that is returned when nothing is found is never ambiguous, or implementing something with FindIndex
as you did. I don't like the out
syntax, but before I write an implementation that doesn't use it, I need some input on what you want returned when nothing was found.
Until then, the TryFind
can be considered OK, since it aligns with previous functionality in .NET, for example Integer.TryParse
. And you do get a decent way to handle nothing found doing
List<Something> stuff = GetListOfStuff();
Something thing;
if (stuff.TryFind(t => t.IsCool, thing)) {
// do stuff that's good. thing is the stuff you're looking for.
}
else
{
// let the user know that the world sucks.
}