Wednesday, April 04, 2007

.Net Generic Finder (VS Automation Model Usage)

I know there are Find/FindAll methods in the System.Collection.* namespace but what I was looking for is something quite different. Here is more or less the scenario:

Suppose you have objects that can be any of the following interfaces: Solution (S), Project (P) or ProjectItem (PI). You don't have a common super type to treat all as polymorphic objects. So if you have a collection of them (Objects) you are not able to have Collection<T> where T is { S | P | PI } because you could have a mix of them (of course at least you have a Collection<Object> but in this case we would not need Generics anyway).

I wanted a finder that allows me to search for an object in this object collection but using the benefits of Generics. I wanted to use the most abstract representation of a collection I could have and I decided to use an IEnumerable parameter. Then I needed to define a Predicate<T> and what I am going to expect is a T or IEnumerable<T> result.

For example: If the col is = { S1, P1, P2, P3, PI1, PI2, PI3 }

The following tests should pass:

1. Finder.FindAll<Solution>(col, delegate( return Predicates.GetNullPredicate<T>())) contains {S1}
2. Finder.FindAll<Project>(col, delegate( return Predicates.GetNullPredicate<T>())) contains {P1, P2, P3}
3. Finder.FindAll<ProjectItem>(col, delegate( return Predicates.GetNullPredicate<T>())) contains {PI1, PI2, PI3}

So I am able to get a IEnumerable<T> where T is { S | P | PI }. I could also specify any other predicate to evaluate specific properties of each T. Notice that I am using the Predicates.Is<T> helper method I published in my previous post to validate if the predicate can be evaluated. I am also using the yield support to collect the result.

public static class Finder
{
public static T Find<T>(IEnumerable elements, Predicate<T> predicate) where T : class
{
IEnumerator<T> enumerator = Find(elements, predicate, true).GetEnumerator();
return enumerator.MoveNext() ? enumerator.Current : null;
}

public static IEnumerable<T> FindAll<T>(IEnumerable elements, Predicate<T> predicate) where T : class
{
return Find<T>(elements, predicate, false);
}

private static IEnumerable<T> Find<T>(IEnumerable elements, Predicate<T> predicate, bool returnFirst) where T : class
{
if (null != elements)
{
foreach (object element in elements)
{
if (Predicates.Is<T>(element, predicate))
{
yield return (T)element;
if (returnFirst) yield break;
}
}
}
yield break;
}
}

Labels: ,


Comments: Post a Comment



<< Home

This page is powered by Blogger. Isn't yours?