Exercise Refactoring Calculator
Exercise Refactoring Calculator
In this exercise you will do refactoring to the Calculator solution you created in an earlier
exercise. Refactoring is when you take an existing code base and change it by for instance
breaking out code from events to methods making the code cleaner and easier to read and
reuse, that is exactly what you will do in this exercise.
The first refactoring you will do is to add regions to logically separate the constructor,
events, constants and variables from each other by moving the constants into a Constants
region, variables into a Variables region, the constructor into a Constructors region and all
the control events into a Control Events region. Also add a region called Methods for the
refactored methods.
Create a method called AddDigit which will add a digit to the calculator value; copy the code
from the btnNumber_Click event and paste it into the AddDigit method body. Change the
code to use the two string parameters you pass into the AddDigit method instead of using
the label directly. Return the concatenated text from the method using a return statement.
Call the AddDigit method from the btnNumber_Click event passing in the Text property
values from the lblValue label and the currently clicked button as parameters.
lblValue.Text = AddDigit(lblValue.Text, btn.Text);
Create a void method called DeleteDigit which takes a reference (ref) string parameter and
a regular string parameter. The reference parameter can be used to send in data and to
return data from the method. Cut all code except the first and last code lines from the
btnDelete_Click event and paste it into the Delete method then change the pasted code to
use the passed in parameters instead of using the label directly. Call the Delete method from
the btnDelete_Click event where the code you cut out was located between the two
remaining code lines. Pass in the newValue variable as the first parameter by reference
using the ref keyword and the text in the lblValue as the second parameter.
Create a method called AddDecimal and modify and use the code form the btnDecimal
_Click event in it; the method should return a string and take a string as a parameter.
Remove all code from the event and assign the result from a call the AddDecimal to the
lblValue label.
lblValue.Text = AddDecimal(lblValue.Text);
Create a method called ToggleSign and modify and use the code form the btnSign_Click
event in it; the method should return a string and take a string as a parameter. Remove all
code from the event and assign the result from a call the ToggleSign to the lblValue label.
lblValue.Text = ToggleSign(lblValue.Text);
The btnEquals_Click event can be refactored into three methods. Create a method called
CanCalculate which will check that the labels contain text, call the CanCalculate method in
the first if-statement of the event and exit from the method with a return statement if the
result of the method call is true.
if (CanCalculate()) return;
Create a method called EndsWithDecimalSign which return a string and take a string as a
parameter; the purpose of this method is to make sure that the value in the labels involved
in the calculations don't end with a decimal character. Copy the code that checks if a label
end with a decimal from the event and modify the code to not use the label directly and
instead use the passed in string parameter. Replace the two checks in the event with calls to
the EndsWithDecimalSign method and assign the result to the Text property of the
lblFirstValue and lblValue respectively.
lblFirstValue.Text = EndsWithDecimalSign(lblFirstValue.Text);
lblValue.Text = EndsWithDecimalSign(lblValue.Text);
Create a void method called Calculate which takes three double parameters and a string
parameter, the first double parameter should be declared as an out parameter which mean
that no value can be passed into the method through that parameter but a value can be
passed out through it. Cut out the if- and else if-statements performing the calculation in the
btnEquals_Click event and paste it into the Calculate method; make sure that the out
parameter is assigned the result of the calculations and that its default value is 0d. Call the
Calculate method from the event where you cut out the code.
Open the btnSqrt_Click event and replace the decimal character check with a call to the
EndsWithDecimalSign method.
lblValue.Text = EndsWithDecimalSign(lblValue.Text);
Adding regions
1. Open the Calculator project you created in chapter 3.
2. Create a region called Constants around the constants in the form's code-behind
file.
3. Create a region called Variables around the memory variable.
4. Create an empty region called Methods; you will add methods in this region as you
do refactoring to the code in this exercise.
5. Create a region called Constructors around the Form1 constructor.
6. Create a region called Control Events surrounding all the Click events and the Load
event.
The complete code for the AddDigit method look like this:
#region Methods
private string AddDigit(string labelText, string buttonText)
{
if (labelText == noValue)
labelText = String.Empty;
labelText += buttonText;
return labelText;
}
#endregion
The complete code for the DeleteDigit method look like this:
private void DeleteDigit(ref string newValue, string value)
{
int length = Convert.ToInt32(value.Length);
if (length > 1)
newValue = value.Substring(0, length - 1);
if (newValue.Equals(minusSign))
newValue = noValue;
}
The complete code for the AddDecimal method look like this:
private string AddDecimal(string value)
{
bool hasDecimal = value.Contains(decimalSign);
if (!hasDecimal)
value += decimalSign;
return value;
}
The complete code for the ToggleSign method look like this:
private string ToggleSign(string value)
{
bool hasSign = value.Contains(minusSign);
if (hasSign)
value = value.Replace(minusSign, String.Empty);
else if (value != noValue)
value = value.Insert(0, minusSign);
return value;
}
The complete code for the EndWithDecimalSign method look like this:
private string EndsWithDecimalSign(string value)
{
var endsWithDecimalSign = value.EndsWith(decimalSign);
int length = Convert.ToInt32(value.Length);
if (endsWithDecimalSign)
value = value.Substring(0, length - 1);
return value;
}
The complete code for the Calculate method look like this:
private void Calculate(out double result, double value1, double value2,
string mathFunction)
{
result = 0d;
if (mathFunction.Equals(plusSign))
result = value1 + value2;
else if (mathFunction.Equals(minusSign))
result = value1 - value2;
else if (mathFunction.Equals(divisionSign))
result = value1 / value2;
else if (mathFunction.Equals(multiplicationSign))
result = value1 * value2;
}
The btnEquals_Click event
1. Locate the btnEquals_Click event.
2. Replace the content of the first if-statement with a call to the CanCalculate method.
if (CanCalculate()) return;
3. Replace the code checking if the lblFirstValue label ends with a decimal with a call to
the EndsWithDecimalSign method passing in the value lblFirstValue.Text property
and assign the result to the same property.
lblFirstValue.Text = EndsWithDecimalSign(lblFirstValue.Text);
5. Replace the if- and else if-statements with a call to the Calculate method passing in
the four variables.
Calculate(out result, value1, value2, mathFunction);
6. Run the application and do some calculations to make sure that the application
works as it is supposed to.
7. Close the application.
lblFirstValue.Text = EndsWithDecimalSign(lblFirstValue.Text);
lblValue.Text = EndsWithDecimalSign(lblValue.Text);
lblMathFunction.Text = String.Empty;
lblFirstValue.Text = String.Empty;
lblValue.Text = result.ToString("F3");
}
The btnSqrt_Click event
1. Locate the btnSqrt_Click event.
2. Replace the code checking if the lblValue label ends with a decimal with a call to the
EndsWithDecimalSign method passing in the value lblValue.Text property and
assign the result to the same property.
lblValue.Text = EndsWithDecimalSign(lblValue.Text);
3. Run the application and calculate some square roots to make sure that the
application works as it is supposed to.
4. Close the application.
lblValue.Text = EndsWithDecimalSign(lblValue.Text);