C#: Refactoring to functional collection parameters
I wrote about a month or so ago about the functional collection parameters now available in C# and certainly one of the most fun refactorings for me is trying to get code written using a for loop into a state where it is using one of these.
With a bit of help from my colleague James Crisp, these are some of the most common refactorings that I have come across so far.
There’s a little bit of repetition with regards to my previous post but I think it’s interesting to see the procedural approach to solving this problems versus the functional approach.
For the sake of the examples, the following classes are common:
public class Foo { private String bar; private String baz; private readonly bool specialFlag; public Foo(string bar, string baz, bool specialFlag) { this.bar = bar; this.baz = baz; this.specialFlag = specialFlag; } public bool HasSpecialFlag() { return specialFlag; } } public class NewFoo { public NewFoo(Foo foo) { } } public class NumericFoo { public int Value { get; set; } }
Going from one collection to another conditionally
var foos = new List<Foo> {new Foo("bar1", "baz2", true), new Foo("bar2", "baz2", false)}.Where(foo => foo.HasSpecialFlag()); var newFoos = new List<NewFoo>(); foreach (var foo in foos) { newFoos.Add(new NewFoo(foo)); }
We started off well using the ‘Where’ method to reduce the original list but we can do even better!
var foos = new List<Foo> {new Foo("bar1", "baz2", true), new Foo("bar2", "baz2", false)}; foos.Where(foo => foo.HasSpecialFlag()) .Select(foo => new NewFoo(foo));
Not significantly less code but it removes the need for more state in our code and makes the code more expressive at the same time which can only be a good thing.
Returning just one result
I came across some code last week which was iterating through a collection and then returning the first item which matched a certain criteria.
This would be useful if we wanted to get the first Foo object which has the special flag set for example.
private Foo GetSpecialFoo(List<Foo> foos) { foreach (var foo in foos) { if(foo.HasSpecialFlag()) { return foo; } } return null; }
My initial thoughts on coming upon this code were that it should be possible to get rid of the loop but I wasn’t sure how to do the return. Luckily the ‘First’ method solves this problem.
private Foo GetSpecialFoo(List<Foo> foos) { return foos.Where(foo => foo.HasSpecialFlag()).First(); }
Accumulating some values
Adding values in collections together is surely one of the most common operations we do and functional collection parameters can help us here too.
var numericFoos = new List<NumericFoo> {new NumericFoo {Value = 2}, new NumericFoo {Value = 5}}; int total = 0; foreach (var numericFoo in numericFoos) { total += numericFoo.Value; }
Introducing a functional approach here gives us the following code:
var numericFoos = new List<NumericFoo> {new NumericFoo {Value = 2}, new NumericFoo {Value = 5}}; int total = numericFoos.Sum(foo => foo.Value);
Pingback: Reflective Perspective - Chris Alcock » The Morning Brew #278
Pingback: Dew Drop - February 3, 2009 | Alvin Ashcraft's Morning Dew
Pingback: Functional Collection Parameters: A different way of thinking about collections at Mark Needham