ReSharper 2024.3 Help

Reduce algorithm complexity and promote modularity

Just about every developer has found himself in a situation where they had a complicated algorithm in a single, virtually unreadable method, that was entangled together with other methods in a class. For example, say you have a general-purpose class for solving equations:

public class EquationSolvers { public static Tuple<double, double> Quadratic(double a, double b, double c) { double disc = b*b - 4*a*c; if (disc < 0) throw new ArgumentException("Cannot solve equation with complex roots"); double sqrt = Math.Sqrt(disc); return new Tuple<double, double>( (-b + sqrt) / (2 * a), (-b - sqrt) / (2 * a)); } // other solvers here }

The above equation solver is hard-coded, meaning that to substitute a different solver, you would have to manually replace each instance. Let’s start by taking it out into a separate class. To do this, we use the Move to Another Type refactoring F6:

Modularity with ReSharper

Then, we need to specify the class to move the method to. In order to separate concerns better, we pick a separate class called QuadraticEquationSolver for this:

Modularity with ReSharper

Now that the method has been moved, let’s try taking the discriminant out to a separate calculation. This is easy — we select the discriminant calculation and invoke the Extract Method refactoring Control+Alt+M:

Modularity with ReSharper

Now, all we need to do is to give the new method a name:

Modularity with ReSharper

And it’s done:

private static double CalculateDiscriminant(double a, double b, double c) { return b * b - 4 * a * c; }

Now, let’s suppose that, after a while, we find a safer solver for quadratic equations. To factor it into the program, we’ll first need to create an abstract base class QuadraticEquationSolverBase. We use the Extract Superclass refactoring refactoring available in the Refactor This menu Control+Shift+R:

Modularity with ReSharper

In the dialog that shows up, we get to pick which members will be promoted upwards. We only want the CalculateDiscriminant method:

Modularity with ReSharper

We add an abstract definition of the Calculate() method (previously called Quadratic()) and end up with the following base class:

public abstract class QuadraticEquationSolverBase { protected double CalculateDiscriminant(double a, double b, double c) { return b*b - 4*a*c; } public abstract Tuple<double, double> Calculate(double a, double b, double c); }

We also got rid of the static keyword anywhere with the assumption that the implementations of QuadraticEquationSolverBase will be handled by a lifetime manager within our code. Consequently, ReSharper reminds us to add the override keyword to the renamed Calculate method in our QuadraticEquationSolver class:

Modularity with ReSharper

Now, let’s say we found a safer version of the quadratic equation solver. Let’s implement it. First, we use the Create derived type context action on our base class:

Then, we are asked to implement members on this type, which we do:

Finally, we provide an implementation, making use of the base class’ CalculateDiscriminant() method:

class SafeQuadraticEquationSolver : QuadraticEquationSolverBase { public override Tuple<double, double> Calculate(double a, double b, double c) { double disc = CalculateDiscriminant(a, b, c); if (disc < 0) throw new ArgumentException("Cannot solve equation with complex roots"); double q = -0.5*(b + Math.Sign(b)*disc); return new Tuple<double, double> (q/a, c/q); } }

And we’re done! Now the quadratic equation solver can be easily used, with its configuration and instantiation typically handled by an IoC container.

Last modified: 11 February 2024