Having some confusion with LINQ - c#

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, not IEnumerable<T>, hence you need:
_resources.Cast<LanguageEditorResource>().Where(r => r.IsDirty)
Note that Enumerable.Where is defined on IEnumerable<T>, not IEnumerable - if you have the non-generic type, you need to use Cast<T> (or OfType<T>) to get the right type. The difference being that Cast<T> will throw an exception if it finds something that isn't a T, where-as OfType<T> simply ignores anything that isn't a T. Since you've stated that your collection only contains LanguageEditorResource, it is reasonable to check that assumption using Cast<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 Where extension method(s).
Actually, it would be worth having your collection implement IEnumerable<LanguageResource> - which you could do quite simply using either the Cast<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 that T in the Dictionary<string,T>, and implementing IEnumerable<T> or ICollection<T>). Just a thought.

In addition to Marc G's answer, and if you're able to do so, you might want to consider dropping your custom LanguageResourceCollection class in favour of a generic List<LanguageResource>. This will solve your current problem and get rid of that nasty .NET 1.1ish custom collection.

How can I dig into what LINQ generates to try and see what the problem is?
Linq isn't generating anything here. You can step through with the debugger.
to try and improve my understanding of LINQ and learn 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 produce targets that support this contract. The type that T represents is important!
You could add this method to LanguageResourceCollection:
public IEnumerable<T> ParticularResources<T>()
{
return _dict.Values.OfType<T>();
}
and call it by:
_resources
.ParticularResources<LanguageEditorResource>()
.Where(r => r.IsDirty)
This example would make more sense if the collection class didn't implement IEnumerable< T > against that same _dict.Values . The point is to understand IEnumerable < T > and generic typing.

Related

Why do so many named collections in .NET not implement IEnumerable<T>?

Random example:
ConfigurationElementCollection
.Net has tons of these little WhateverCollection classes that don't implement IEnumerable<T>, which means I can't use Linq to objects with them out of the box.
Even before Linq, you'd think they would have wanted to make use of generics (which were introduced all the way back in C# 2 I believe)
It seems I run across these annoying little collection types all the time.
Is there some technical reason?
The answer is in the question title: "named collections". Which is the way you had to make collections type-safe before generics became available. There are a lot of them in code that dates back to .NET 1.x, especially Winforms. There was no reasonable way to rewrite them using generics, that would have broken too much existing code.
So the named collection type is type safe but the rub is System.Collections.IEnumerator.Current, a property of type Object. You can Linqify these collections by using OfType() or Cast().
As Adam Houldsworth said in a comment already, you simply need to use the Cast<> method.
Example:
var a = new DogCollection();
var allFidos = a.Cast<Dog>().Where(d => d.Name == "Fido");

Why Are AsObservable and AsEnumerable Implemented Differently?

The implementation of Enumerable.AsEnumerable<T>(this IEnumerable<T> source) simply returns source. However Observable.AsObservable<T>(this IObservable<T> source) returns an AnonymousObservable<T> subscribing to the source rather than simply returning the source.
I understand these methods are really useful for changing the monad within a single query (going from IQueryable => IEnumerable). So why do the implementations differ?
The Observable version is more defensive, in that you can't cast it to some known type (if it original were implemented as a Subject<T> you'd never be able to cast it as such). So why does the Enumerable version not do something similar? If my underlying type is a List<T> but expose it as IEnumerable<T> through AsEnumerable, it will be possible to cast back to a List<T>.
Please note that this isn't a question on how to expose IEnumerable<T> without being able to cast to the underlying, but why the implementations between Enumerable and Observable are semantically different.
Your question is answered by the documentation, which I encourage you to read when you have such questions.
The purpose of AsEnumerable is to hint to the compiler "please stop using IQueryable and start treating this as an in-memory collection".
As the documentation states:
The AsEnumerable<TSource>(IEnumerable<TSource>) method has no effect other than to change the compile-time type of source from a type that implements IEnumerable<T> to IEnumerable<T> itself. AsEnumerable<TSource>(IEnumerable<TSource>) can be used to choose between query implementations when a sequence implements IEnumerable<T> but also has a different set of public query methods available.
If you want to hide the implementation of an underlying sequence, use sequence.Select(x=>x) or ToList or ToArray if you don't care that you're making a mutable sequence.
The purpose of AsObservable is to hide the implementation of the underlying collection. As the documentation says:
Observable.AsObservable<TSource> ... Hides the identity of an observable sequence.
Since the two methods have completely different purposes, they have completely different implementations.
You're right about the relationship between AsEnumerable and AsObservable wrt the aspect of switching from expression tree based queries to in-memory queries.
At the same time, exposing an Rx sequence based on a Subject<T> is very common, and we needed a way to hide it (otherwise the user could cast to IObservable<T> and inject elements).
A long while ago in the history of Rx pre-releases, we did have a separate Hide method, which was merely a Select(x => x) alias. We never quite liked it and decided to have a place where we deviated from the LINQ to Objects precise mirrorring, and made AsObservable play the role of Hide, also based on users who believed this was what it did to begin with.
Notice though, we do have an extension method called AsObservable on IQbservable<T> as well. That one does simply what AsEnumerable does too: it acts as the hint to the compiler to forget about the expression tree based querying mode and switch to in-memory queries.

Why does IList<T> not provide all the methods that List<T> does? Which should I use?

I have always been taught that programming against an interface is better, so parameters on my methods I would set to IList<T> rather than List<T>..
But this means I have to cast to List<T> just to use some methods, one comes to mind is Find for example.
Why is this? Should I continue to program against interfaces, but continue to cast or revert?
I am a little bit confused why Find (for example) isn't available on the IList<T> which List<T> inherits from.
Personally I would use IList<T> rather than List<T>, but then use LINQ (Select, Where etc) instead of the List-specific methods.
Casting to List<T> removes much of the point of using IList<T> in the first place - and actually makes it more dangerous, as the implementation may be something other than List<T> at execution time.
In the case of lists you could continue programming against interfaces and use LINQ to filter your objects. You could even work with IEnumerable<T> which is even higher in the object hierarchy.
But more generally if the consumer of your API needs to call a specific method you probably haven't chosen the proper interface to expose.
I am a little bit confused why Find
(for example) isn't available on the
IList which List inherits from.
While I'm not privy to the decision process of the designers, there are a few things they were probably thinking.
1) Not putting these methods on IList keeps the intent of the contract clearer. According to MSDN, IList "Represents a collection of objects that can be individually accessed by index." Adding Find would change the contract to a searchable, indexable collection.
2) Every method you put on an interface makes it harder to implement the interface. If all of those methods were on IList, it would be much more tedious to implement IList. Especially since:
3) Most implementations of these methods would be the same. Find and several of the others on List would really be better placed on a helper class. Take for example, ReadOnlyCollection, Collection, ObservableCollection, and ReadOnlyObservableCollection. If I had to implement Find on all of those (pre-LINQ), I would make a helper class that takes IEnumerable and a predicate and just loop over the collections and have the implementations call the helper method.
4) LINQ (Not so much a reason why it didn't happen, more of why it isn't needed in the future.) With LINQ and extension methods, all IEnumerable's now "have" Find as an extension method (only they called it Where).
I think it's because IList can be different collection types (ie. an IEnumerable of some sort, an array or so).
You can use the Where extension method from System.Linq. Avoid casting back to List from IList.
If you find that the IList<T> parameter being passed between various classes is consistently being recast into List<T>, this indicates that there is a fundamental problem with your design.
From what you're describing, it's clear that you want to use polymorphism, but recasting on a consistent basis to List<T> would mean that IList<T> does not have the level of polymorphism you need.
On the other side of the coin, you simply might be targeting the wrong polymorphic method (e.g., Find rather than FirstOrDefault).
In either case, you should review your design and see what exactly you want to accomplish, and make the choice of List<T> or IList<T> based on the actual requirements, rather than conformity to style.
If you expose your method with a IList<> parameter, someone can pass, for exemple, a ReadOnlyCollection<>, witch is an IList<> but is not a List<>. So your API will crash at runtime.
If you expose a public method with a IList<> parameter, you cannot assume that it is a specific implementation of an IList<>. You must use it as an IList<> an nothing more.
If the list is some part of an Api or service that is exposed then it is probably better to have as an IList to allow the change of the implementation internally.
There is already much discussion on this topic.
No, in this case it has no sense to program to interfaces, because your List is NOT an IList, having extra methods on it.

Why return a collection interface rather than a concrete type? [duplicate]

This question already has answers here:
List<T> or IList<T> [closed]
(18 answers)
Closed 8 years ago.
I've noticed in other people's code that methods returning generic collections will almost always return an interface (e.g. IEnumerable<T> or IList<T>) rather than a concrete implementation.
I have two related questions. Firstly, why (if at all) is it considered better to return an interface? Secondly, is there a collection interface that includes the Sort method (as List<T> does)?
For the first question: if you return an interface, you retain more flexibility. You can change the implementation later to return a different concrete type. On the other hand, it obviously gives the caller less information, so they may not be able to perform certain operations. (e.g. if you return List<T>, the caller can use ConvertAll etc... which they can't if you only declare that you return IList<T>.) In some situations it's worth specifying the concrete type; I generally prefer to at least start with interfaces, and only move to put the concrete type as the return type if I find that I frequently want to use the extra methods available.
Secondly, no standard collection interfaces have a Sort method. On the other hand, you could write an extension method to sort any IList<T>. Personally I usually prefer the LINQ OrderBy, OrderByDescending, ThenBy and ThenByDescending methods... although they return a new sequence, rather than sorting in place.
From C# - List or IList
If you are exposing your class through
a library that others will use, you
generally want to expose it via
interfaces rather than concrete
implementations. This will help if you
decide to change the implementation of
your class later to use a different
concrete class. In that case the
user's of your library won't need to
update their code since the interface
doesn't change.
If you are just using it internally,
you may not care so much, and using
List may be ok.
We use interfaces to give us more flexibility in our implementation. So if your method has the return type of IEnumerable, you could change the object that it returns from a List to an Array without altering the objects that depend on the method.
It's also expressive: if you are returning an IEnumerable, when the object is being used it's clear to the coder that we only care that it's some sort of collection, rather than a specific type
I can't speak for everyone but generally I do it just because I like to only return what I need.Why pass back a full blown collection when all you need is an enumerable collection that can be iterated over.
As to the other part of your question you can always use an IList and then use LINQ to sort:
list.OrderBy(a=>a.Id);

Will Microsoft ever make all collections useable by LINQ?

I've been using LINQ for awhile (and enjoy it), but it feels like I hit a speedbump when I run across .NET specialized collections(DataRowCollection, ControlCollection). Is there a way to use LINQ with these specialized controls, and if not do you think Microsoft will address this in the next release of the framework? Or are we left to iterate over these the non-LINQ way, or pull the items out of the collection into LINQ-able collections ourselves?
The reason why collections like ControlCollection do not work with LINQ is that they are not strongly typed. Without an element type LINQ cannot create strongly typed methods. As long as you know the type you can use the Cast method to create a strongly typed enumeration and hence be used with LINQ. For example
ControlCollection col = ...
var query = col.Cast<Control>().Where(x => ...);
As to will Microsoft ever make these implement IEnumerable<T> by default. My guess is no here. The reason why is that doing so is a breaking change and can cause expected behavior in code. Even simply implementing IEnumerable<Control> for ControlCollection would cause changes to overload resolution that can, and almost certainly will, break user applications.
You should be able to do something like this:
myDataRowCollection.Cast<DataRow>().Where.....
and use Linq that way. If you know what the objects in the collection are, then you should be able to use that.
The reason for this is: Collections which do not implement IEnumerable<T> or IQueryable, can not be iterated in LINQ

Categories