One of the things I have come to love about Linq is how you can focus more on declarative programming: focusing on what you want to accomplish rather than how.
See for example below - I have a generic list of SolutionDescriptor instances (a class in my project that describes a position in a Visual Studio solution), and want to search if for the best match to the language and Visual Studio version preferences in a UserProfile instance:
Note the three queries against the List, each one a Linq expression, starting with an attempt at an exact match, then match on language preference, and finally one on just version:
private SolutionDescriptor FindBestMatch(List<SolutionDescriptor> startpoints)
{
UserProfile profile = Singleton<UserProfileManager>.Instance.Profile;
// first, search for an exact match
SolutionDescriptor match = (
from sd in startpoints
where sd.Language == profile.PreferredLanguage && sd.VSVersion == profile.PreferredVSVersion
select sd).FirstOrDefault<SolutionDescriptor>();
if (match == null)
{
// next, search by just language
match = (
from sd in startpoints
where sd.Language == profile.PreferredLanguage
select sd).FirstOrDefault<SolutionDescriptor>();
if (match == null)
{
// finally, search just by VS version
match = (
from sd in startpoints
where sd.VSVersion == profile.PreferredVSVersion
select sd).FirstOrDefault<SolutionDescriptor>();
}
}
return match;
}
The FirstOrDefault<> method is a way to either get the first match, or the default for the type in question, which is null for my class.