Suppose you have a complicated mathematical calculation to do, that involves performing rounding. Suppose that sometimes you want the rounding to be round to even (aka bankers' rounding), but other times you want round away from zero (aka 'round up [in absolute value]').
Now, you could write two methods:
double DoTheCalculationWithRoundToEven(double input1, double input2)
{
var intermediate1 = Math.Pow(input1, input2);
// more calculations...
var intermediate5 = Math.Round(intermediate4, MidpointRounding.ToEven);
// more calculations...
var intermediate10 = Math.Abs(intermediate9);
return intermediate10;
}
double DoTheCalculationWithRoundAwayFromZero(double input1, double input2)
{
var intermediate1 = Math.Pow(input1, input2);
// more calculations...
var intermediate5 = Math.Round(intermediate4, MidpointRounding.AwayFromZero);
// more calculations...
var intermediate10 = Math.Abs(intermediate9);
return intermediate10;
}
with the two methods being the same except for that one line in the middle.
Now, this works, BUT you've got duplicated code and the very real possibility that some future maintainer (for example, a future you) will change one version of the intermediate2
to intermediate3
and forget about the other.
A delegate type and parameter can solve this duplication.
First declare the delegate type:
public delegate double Rounder(double value);
This says that a Rounder
is a method that accepts a double
and returns a double
.
Next, have one calculation method that accepts a Rounder
and uses it to round:
double DoTheCalculation(double input1, double input2, Rounder rounder)
{
var intermediate1 = Math.Pow(input1, input2);
// more calculations...
var intermediate5 = rounder(intermediate4);
// more calculations...
var intermediate10 = Math.Abs(intermediate9);
return intermediate10;
}
Finally, when you want the calculation done, pass an appropriate Rounder
. You can spell it all out with methods:
double RounderAwayFromZero(double value)
{
return Math.Round(value, MidpointRounding.AwayFromZero);
}
// same for ToEven
then call one of:
var result = DoTheCalculation(input1, input2, RounderAwayFromZero);
or
var result = DoTheCalculation(input1, input2, RounderToEven);
but C# allows you to do this all inline with lambdas:
var result = DoTheCalculation(input1, input2,
value => Math.Round(value, MidpointRounding.AwayFromZero));
where the lambda expression defines a method with the correct signature to be a Rounder
.