In making the most of your code, you have two options: you can use generic methods or reusable delegates.
Using Generic Methods
Of course, one of the benefits of generic methods is that they can be reused with collections of different types. A very simple example is a function that sorts a collection and writes it to the console window:
static void WriteSortedValues
{
list.Sort();
list.ForEach(
delegate(T item) { Console.WriteLine(item); }
)
}
Note: ForEach Uses Action Delegates
In the above example, we’re using the ForEach method with an action delegate. An action delegate is another type of anonymous delegate, only it doesn’t return anything. The idea behind an action delegate is that it defines an action to be performed for each item in the collection. This compares with predicate delegates, which contain the decision logic. This action delegate uses the same logic that we saw with Find and FindAll in “How do I filter filtering generic collections items in a generic collection generic collections filtering ?”.
The WriteSortedValues function is generic, as indicated by the
Predicates.aspx.cs (excerpt)
private void SortingDemonstration()
{
string[] names = { “Bob”, “Sue”, “Jim”, “Edgar” };
int[] values = { 456, 234, 567, 123, 890 };
DateTime[] dates = {
new DateTime(1950,2,3),
new DateTime(1970,4,5),
new DateTime(2000,1,1)
};
WriteSortedValues(new List
WriteSortedValues(new List
WriteSortedValues(new List
}
We can’t necessarily use this solution with a collection of custom objects, such as List
Using Reusable Delegates
Most of our samples so far have implemented predicates and actions as anonymous delegates. We looked at the reasons for this (simpler code, local variable capturing) in “How do I filter filtering generic collections items in a generic collection generic collections filtering ?”. However, you should keep an eye out for delegates that can be reused, and promote them to methods.
For example, let’s assume that an application we’ve written for our employer consists of multiple classes, including Customers, Employees, Stores, and an Address structure.[4] This Address contains a Region property.
Our company is headquartered in California, so for various reasons (sales tax, employee taxes, benefits, and so on), we may want to filter our different lists so that our results include only items whose Region is California.
As such, our delegate method for retrieving Californian employees might look like this:
return employeeList.Find(
p.Address.Region == “California”
);
We can move this into a reusable delegate method as follows:
Predicates.aspx.cs (excerpt)
public static bool IsCalifornian(Person p)
{
return (p.Address.Region == “California”);
}
Now we can use that method with any list that contains the Address structure—for example, a list of Employees or Customers:
Predicates.aspx.cs (excerpt)
public List
{
List
return employees.FindAll(Person.IsCalifornian);
}
public List
{
List
customers.RemoveAll(Person.IsCalifornian);
return customers;
}
In the above code listing, we’re using the same predicate in two different ways. In the first example, GetCaliforniaEmployees, we’re using it with FindAll to return all employees who have a Californian address. In the second example, GetNonCaliforniaCustomers, we’re using the predicate with RemoveAll to remove all Customers with Californian addresses from the customer list.
[3]For more information on implementing the IComparable interface, see David Hayden’s excellent blog post.
[4]A structure, represented by the keyword struct in C#, is a composite data type. A structure can contain fields, methods, constants, constructors, properties, indexers, operators and other structure types.