C#: A failed attempt at F#-ish pattern matching
A few weeks ago we had some C# code around calcuations which had got a bit too imperative in nature.
The code looked roughly like this:
public class ACalculator
{
public double CalculateFrom(UserData userData)
{
if(userData.Factor1 == Factor1.Option1)
{
return 1.0;
}
if(userData.Factor2 == Factor2.Option3)
{
return 2.0;
}
if(userData.Factor3 == Factor3.Option2)
{
return 3.0
}
return 0.0;
}
}
I think there should be a more object oriented way to write this code whereby we push some of the logic onto the 'UserData' object but it struck me that it reads a little bit like pattern matching code you might see in F#.
I decided to drive the code to use a dictionary which would store functions representing each of the conditions in the if statements:
public class ACalculator
{
private Dictionary<Func<UserData, bool>, double> calculations;
public ACalculator()
{
calculations = new Dictionary<Func<UserData,bool>,double>
{
{u => u.Factor1 == Factor1.Option1, 1.0},
{u => u.Factor2 == Factor2.Option3, 2.0},
{u => u.Factor3 == Factor3.Option2, 3.0}
};
}
public double CalculateFrom(UserData userData)
{
var calculation = calculations.Keys.FirstOrDefault(calc => calc(userData));
if(calculation != null)
{
return calculations[calculation];
}
return 0.0;
}
}
It’s less readable than it was before and it’s not obvious that the adding of the functions to the dictionary needs to be in that order in order for it to work.
I’ve simplified the real example a bit to show the idea but I don’t think it works as the best abstraction in this situation either way although it was an interesting experiment.
About the author
I'm currently working on short form content at ClickHouse. I publish short 5 minute videos showing how to solve data problems on YouTube @LearnDataWithMark. I previously worked on graph analytics at Neo4j, where I also co-authored the O'Reilly Graph Algorithms Book with Amy Hodler.