Extension Methods on Generics
Sometimes when I’m coding I have the “oh wouldn’t it be nice if this was possible” moments, which turn into great moments when I find to my surprise on occasion that they are.
One such moment recently was realising that I can create extension methods against generic types – something that I had never thought about before. In hindsight of course this is possible, since a specified generic type is an actual static type.
The situation I found myself in recently was whilst coding a bit of filtering code to allow the user to set up dynamic filters. As such I needed a list of comparison operators for which I created an enumerated list as per listing 1 below.
public enum ComparisonOperator { EqualTo, NotEqualTo, GreaterThan, LessThan, GreaterThanOrEqualTo, LessThanOrEqualTo, StartsWith, EndsWith, Contains, IsEmpty, IsNotEmpty }
Since most of the fields that the user could filter on would have similar comparison operators, I found myself adding in the same bunch for each filter type, i.e. a string based field would have ‘StartsWith’, ‘EndsWith’, ‘Contains’, etc.
My “oh wouldn’t it be nice if…” moment was wouldn’t it be nice if I could create an extension method to add in default sets of comparison operators to lists, and I found that I could as per the code in listing 2.
public static class ComparisonOperatorEnum { public static IList AddNumericOperators(this IList comparisonOperatorList) { return new List<ComparisonOperator>() { ComparisonOperator.EqualTo, ComparisonOperator.IsEmpty, ComparisonOperator.IsNotEmpty, ComparisonOperator.LessThan, ComparisonOperator.LessThanOrEqualTo, ComparisonOperator.GreaterThan, ComparisonOperator.GreaterThanOrEqualTo, ComparisonOperator.NotEqualTo }; } public static IList AddStringOperators(this IList comparisonOperatorList) { return new List<ComparisonOperator>() { ComparisonOperator.EqualTo, ComparisonOperator.NotEqualTo, ComparisonOperator.IsEmpty, ComparisonOperator.IsNotEmpty, ComparisonOperator.Contains, ComparisonOperator.StartsWith, ComparisonOperator.EndsWith }; } public static IList AddReferenceOperators(this IList comparisonOperatorList) { return new List<ComparisonOperator>() { ComparisonOperator.EqualTo, ComparisonOperator.NotEqualTo, ComparisonOperator.IsEmpty, ComparisonOperator.IsNotEmpty }; } public static IList AddBooleanOperators(this IList comparisonOperatorList) { return new List<ComparisonOperator>() { ComparisonOperator.EqualTo, ComparisonOperator.NotEqualTo, ComparisonOperator.IsEmpty, ComparisonOperator.IsNotEmpty }; } }
This means that my filter definition code is now shorter and clearer, and for those of you who like such things, more fluent.
myFilteredField.ComparisonOperators = new List().AddStringOperators();
It also means that if I add in any additional comparison operators in the future, then I won’t have to hunt down any filtering code and manually add them in.
A happy C# camper.