Having some confusion with LINQ

Some background information;

  • LanguageResource is the base class
  • LanguageTranslatorResource and LanguageEditorResource inherit from LanguageResource
  • LanguageEditorResource defines IsDirty property
  • LanguageResourceCollection is a collection of LanguageResource
  • LanguageResourceCollection internally stores LanguageResources in Dictionary<string, LanguageResource> _dict

  • LanguageResourceCollection.GetEnumerator () returns _dict.Values.GetEnumerator()

I have a LanguageResourceCollection _resources that only contains LanguageEditorResource objects and wants to use LINQ to enumerate those that are dirty, so I tried the following. My specific questions are in bold.

  • _resources.Where(r => (r as LanguageEditorResource).IsDirty)



    nor where Intellisense does not show other LINQ methods, but I code it anyway and I was told "LanguageResourceCollection does not contain a definition for" Where "and extension method ...".

    Why doesn't the way the LanguageResourceCollection implements IEnumerable allow it to support LINQ?

  • If I change the query to

    (_resources as IEnumerable<LanguageEditorResource>).Where(r => r.IsDirty)



    Intellisense it displays LINQ methods and compiles the solution. But at runtime I get an ArgumentNullException "The value cannot be null. Parameter name: source".

    Is this a problem in my LINQ code?
    Is this a problem with general class design?
    How can I dig into what LINQ is generating to try and figure out what the problem is?

My goal in this question is not to get a solution for a specific problem, since I have to solve it now using other (non-LINQ) means, but to try to improve my understanding of LINQ and find out how I can improve the design of my classes. to work better with LINQ.

0


source to share


3 answers


It looks like your collection implements IEnumerable

, not IEnumerable<T>

, so you need to:

_resources.Cast<LanguageEditorResource>().Where(r => r.IsDirty)

      

Note that it Enumerable.Where

is defined on IEnumerable<T>

, not IEnumerable

- if you have a non-generic type, you need to use Cast<T>

(or OfType<T>

) to get the correct type. The difference is that it Cast<T>

throws an exception if it finds something that is not T

, where-as OfType<T>

simply ignores everything that is not T

. Since you have stated that your collection contains only LanguageEditorResource

, it is reasonable to test this assumption using Cast<T>

, instead of silently discarding the data.



Also check that you have "using System.Linq" (and referenced to System.Core (.NET 3.5; else LINQBridge with .NET 2.0) to get the extension method Where

.

It would actually make sense to implement your collection IEnumerable<LanguageResource>

- which you could simply do with a method Cast<T>

or iterator ( yield return

) block .

[edit] To build on Richard Poole's note, you can write your own generic container here, presumably with T : LanguageResource

(and using T

in Dictionary<string,T>

and implementing IEnumerable<T>

or ICollection<T>

)). Just a thought.

+6


source


In addition to Marc G's answer, and if you are able to do so, you may need to ditch your custom class LanguageResourceCollection

in favor of a generic one List<LanguageResource>

. This will fix your current problem and get rid of that nasty .NET 1.1ish custom collection.



+1


source


How can I dig into what LINQ is generating to try and figure out what the problem is?

Linq doesn't generate anything here. You can go through the debugger.

to try and improve my understanding of LINQ and find out how I can improve the design of my classes to work better with LINQ.

System.Linq.Enumerable methods rely heavily on the IEnumerable <T> contract. You need to understand how your class can create goals that support this contract. The type that T represents is important!

You can add this method to LanguageResourceCollection:

public IEnumerable<T> ParticularResources<T>()
{
  return _dict.Values.OfType<T>();
}

      

and call it:

_resources
  .ParticularResources<LanguageEditorResource>()
  .Where(r => r.IsDirty)

      

This example makes sense if the collection class did not implement IEnumerable <T> against the same _dict.Values. The point is to understand IEnumerable <T> and typical typing.

+1


source







All Articles