A scenario where LINQ is too dynamic (answered)

The situation I talked about in my previous post had one very big issue: LINQ sometimes just is too dynamic… ;)
The fact that I changed the value for the Ranking property for each SpecificObject that got matched, made the primary LINQ query have a different outcome. LINQ uses lazy evaluation and  because of that, the contents of finalGroups and exitGroups changed every time I changed the Ranking value for one of the SpecificObjects. Each time the variable containing the outcome of the LINQ query is iterated through, the query is evaluated again. This made that the matching was all off, and I ended up with a bunch of exit groups that got matched!

To have a simple solution, I did the following. This holds the final and exit objects in a ‘static’ list in stead of a dynamic query result. This way, the SpecificObjects in the finalObjects and exitObjects lists stay the same, regardless of the changes you make to any of the SpecificObjects.

int count;
int numberOfPossibilities;
IEnumerable<SpecificObject> temp;
List<SpecificObject> finalObjects;
List<SpecificObject> exitObjects;

count = 0;
finalObjects = new List<SpecificObject>();
exitObjects = new List<SpecificObject>();

temp = from SpecificObject specificObject in AllSpecificObjects
       orderby specificObject.Ranking
       select specificObject;

foreach (SpecificObject specificObject in temp)
    if (count < numberOfPossibilities)

By the way, we have a winner. Ruud Campsteijn was pretty quick with the right answer!

A scenario where LINQ is too dynamic

While developing an algorithm to match preferences to possibilities, I had to sort a generic list of a specific object type (SpecificObject). The first x objects would be matched, the rest would be excluded because of the number of available places. To determine the group of objects that would be matched and the group that would be excluded, I did something like this:

IEnumerable<SpecificObject> sortedObjects;
IEnumerable<SpecificObject> finalObjects;
IEnumerable<SpecificObject> exitObjects;

sortedObjects = from SpecificObject specificObject in AllSpecificObjects
                orderby specificObject.Ranking
                select specificObject;

finalObjects = sortedObjects.Take<SpecificObject>(numberOfPossibilities);
exitObjects = sortedObjects.Skip<SpecificObject>(numberOfPossibilities);

Next I would iterate through the possibilities and look for a match in (a subset of) the ‘finalObjects’ list. To be sure the matching would be done honestly during this process, I changed the value for the Ranking property after a positive match. This way, SpecificObjects that had no match yet would move up in the ranking and would be matched before SpecificObjects that already had one or more positive matches. Unfortunately, this had a very unwanted side-effect.

Can you think of it? Let me know and put it in the comments. The answer can be found in my next post.

By |June 6th, 2008|.Net, Linq|1 Comment

Selecting all the controls of a specific type, the (built in!) LINQ way

We probably all worked with dynamically generated controls on forms, ASP.NET pages or (user) controls. And I guess we’ve all written for-each statements to loop through the ControlCollection and filter out all the controls of a specific type, right? I wanted to do the same today, so I started by trying to use LINQ for this:
This, as you can see, generated a compile time error:
Could not find an implementation of the query pattern for source type ‘System.Web.UI.ControlCollection’.  ‘Where’ not found.  Consider explicitly specifying the type of the range variable ‘control’.

As the error states, this is easily solved by explicitly specifying the type of the control variable. Because a ControlCollection can contain so many types, it is not strange the compiler asks you to be a bit more precise on the type you will be querying. That looks something like this:

But when I added the System.Linq namespace to my using section, I saw an extra method on the ControlCollection, called OfType<>. This method is one of the extension methods that can be applied to a collection that has a non-parameterized type like a ControlCollection or an ArrayList, because OfType<> extends the type IEnumerable.
Another one of those nice ‘native’ Linq extension methods is the Cast<> method, which pretty much does the same but throws an exception if there are any objects in the collection that cannot be cast to the specified type. And yes, exceptions are sometimes wanted ;)

For more info on the OfType<> method, see: Enumerable.OfType<TResult> Generic Method
For more info on the Cast<> method, see: Enumerable.Cast<TResult> Generic Method

Technorati tags: ,,