Dutton

Playing with Predicate

I came across a problem during recent round of refactoring. Here's a contrived simiIar example.

I have an IEnumerable, MyThings contains a property of type Enum called MyThingType. Scattered around my class I found I had quite a bit of duplicated code consisting of a Linq Where statement to filter the IEnumerable based on a specific values of MyThingType and then perform some additional actions on the result.

var filtereredThings = MyThingsList.Where(t => t.MyThingType == ThingType.ThingA);
// other stuff on filteredThings

All good so far, I extracted the common code into a new private method call which returned my result and took the MyThingType as a parameter to filter on, the problem arose when my last Where statement filtered on two MyThingType values.

private IEnumerable FilterAndProcessThingType(IEnumerable data, ThingType filterType)
{
  var filtereredThings = MyThingsList.Where(t => t.MyThingType == filterType);
  // other stuff on filteredThings and return result
}

I changed my method to take a params parameter for the filter so I can pass a variable number of MyThingType in, but how do I change my Linq?

private IEnumerable FilterAndProcessThingType(IEnumerable data, params ThingType[] filterType)
{
  var filtereredThings = MyThingsList.Where(t => t.MyThingType == ???);
  // other stuff on filteredThings and return result
}

This is where Predicate comes in; a Predicate is a function which returns true or false. This means I can dynamically create one to do my MyThingType check and put it in my Where's Lambda expression.

private IEnumerable FilterAndProcessThingType(IEnumerable data, params ThingType[] typeFilter)
{
  var thingTypeMatcher = new Predicate<tuple<thingtype, thingtype[]="">>(t =>
  {
    var thingType = t.Item1;
    var thingTypeArray = t.Item2;
    return thingTypeArray.Aggregate(false,(current, type) => current | thingType == type);
  });
  var filtereredThings = MyThingsList.Where(t => thingTypeMatcher(new Tuple<thingtype, thingtype[]="">(t.MyThingType, typeFilter));
  // other stuff on filteredThings and return result
}

And that's it, now I can pass a variable number of types to match into my common code.


Share this: