Some background info;
- LanguageResource is the base class
- LanguageTranslatorResource and LanguageEditorResource inherit from LanguageResource
- LanguageEditorResource defines an IsDirty property
- LanguageResourceCollection is a collection of LanguageResource
- LanguageResourceCollection internally holds LanguageResources in
Dictionary<string, LanguageResource> _dict - LanguageResourceCollection.GetEnumerator() returns
_dict.Values.GetEnumerator()
I have a LanguageResourceCollection _resources that contains only LanguageEditorResource objects and want to use LINQ to enumerate those that are dirty so I have tried the following. My specific questions are in bold.
-
_resources.Where(r => (r as LanguageEditorResource).IsDirty)neither Where not other LINQ methods are displayed by Intellisense but I code it anyway and am told ‘LanguageResourceCollection does not contain a definition for ‘Where’ and no extension method…’.
Why does the way that LanguageResourceCollection implements IEnumerable preclude it from supporting LINQ?
-
If I change the query to
(_resources as IEnumerable<LanguageEditorResource>).Where(r => r.IsDirty)Intellisense displays the LINQ methods and the solution compiles. But at runtime I get an ArgumentNullException ‘Value cannot be null. Parameter name: source’.
Is this a problem in my LINQ code?
Is it a problem with the general design of the classes?
How can I dig into what LINQ generates to try and see what the problem is?
My aim with this question is not to get a solution for the specific problem, as I will have to solve it now using other (non LINQ) means, but rather to try and improve my understanding of LINQ and learn how I can improve the design of my classes to work better with LINQ.
It sounds like your collection implements
IEnumerable, notIEnumerable<T>, hence you need:Note that
Enumerable.Whereis defined onIEnumerable<T>, notIEnumerable– if you have the non-generic type, you need to useCast<T>(orOfType<T>) to get the right type. The difference being thatCast<T>will throw an exception if it finds something that isn’t aT, where-asOfType<T>simply ignores anything that isn’t aT. Since you’ve stated that your collection only containsLanguageEditorResource, it is reasonable to check that assumption usingCast<T>, rather than silently drop data.Check also that you have ‘using System.Linq’ (and are referencing System.Core (.NET 3.5; else LINQBridge with .NET 2.0) to get the
Whereextension method(s).Actually, it would be worth having your collection implement
IEnumerable<LanguageResource>– which you could do quite simply using either theCast<T>method, or an iterator block (yield return).[edit] To build on Richard Poole’s note – you could write your own generic container here, presumably with
T : LanguageResource(and using thatTin theDictionary<string,T>, and implementingIEnumerable<T>orICollection<T>). Just a thought.