With .Net 2.0, we have some basic search
functionality baked in to the .Net Framework. With Linq coming out in .Net 3.5,
we will have full querying support on IEnumerable types, but we have quite a bit
of power with .Net 2.0. In this short article, I'll outline how to search
objects in memory with .Net 2.0 or higher.
Consider the following class, Person:
public class Person : IComparable
{
private string _firstName;
private string
_lastName;
public Person(string firstName,
string
lastName)
{
_firstName
= firstName;
_lastName = lastName;
}
public string FirstName
{
get { return _firstName;
}
}
public string
LastName
{
get { return _lastName;
}
}
public string
FullName
{
get { return string.Format("{0} {1}",
FirstName, LastName); }
}
public int CompareTo(object obj)
{
Person person = (Person)obj;
int compareResult =
LastName.CompareTo(person.LastName);
if(compareResult == 0)
{
compareResult = FirstName.CompareTo(person.FirstName);
}
return compareResult;
}
public override string
ToString()
{
return
FullName;
}
}
Consider
this a basic domain object within the application. We have the need to work
with many instances of this class in memory. Assume that there is no need for a
relational database for this application. We pull Person instances in memory
and work with them. Often, we'll need to pare down the set to only include
instances that match some criteria. We could loop through each one and create a
new list with matches, but with .Net 2.0 and "Comparison"(s), we have a more
elegant way. Here is an example.
public void ShouldQueryArray()
{
Person[] people = new Person[]{new Person("Homer", "Simpson"), new
Person("Jeffrey", "Palermo")};
Person[] matches = Array.FindAll<Person>(people, delegate(Person
obj)
{
return
(obj.FirstName.Contains("ome"));
});
foreach(Person
person in matches)
{
Console.WriteLine(person);
}
}
In this example, we can just specify the
condition that causes an instance to match, and we'll get back a new array with
only the matches. In this case, we get the following output:
Homer Simpson
I work with
arrays a lot. In fact, it is my favorite IEnumerable data structure because of
it's power, but it isn't the only structure that supports comparisons (and there
are other methods similar to FindAll, but FindAll is the most common).
public void ShouldQueryIList()
{
List<Person>
list = new List<Person>();
list.Add(new Person("Homer",
"Simpson"));
list.Add(new Person("Jeffrey",
"Palermo"));
List<Person>
matches = list.FindAll(delegate(Person obj)
{
return
(obj.FirstName.Contains("ome"));
});
foreach (Person
person in matches)
{
Console.WriteLine(person);
}
}
Here, we are using the
List<T> class for our search. The following example is more complex.
This illustrates that the matching criteria can be as complicated as you need it
to be.
public void ShouldQueryArrayWithComplexComparison()
{
Person[] people = new Person[] { new Person("Homer", "Simpson"), new
Person("Jeffrey", "Palermo") };
Person[] matches = Array.FindAll<Person>(people, delegate(Person
obj)
{
return
(obj.FirstName.StartsWith("j", StringComparison.InvariantCultureIgnoreCase)
&& obj.LastName.EndsWith("mo"));
});
foreach (Person person in
matches)
{
Console.WriteLine(person);
}
}
By the way, if you aren't
familiar with the "delegate" keyword, this is an anonymous method. I could
refactor it into a private method, but I'm using it inline instead. In short,
FindAll just requires a delegate. However you wish to provide it is fine.