0% found this document useful (0 votes)
18 views11 pages

Exercise Refactoring Calculator

This document outlines a refactoring exercise for a calculator application in C#. It details the steps to improve code organization by creating regions for constants, variables, constructors, control events, and methods, as well as implementing specific methods for adding digits, deleting digits, adding decimals, toggling signs, and performing calculations. The document provides complete code examples for each method and event handler to demonstrate the refactoring process.

Uploaded by

Mouhib Mouhib
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views11 pages

Exercise Refactoring Calculator

This document outlines a refactoring exercise for a calculator application in C#. It details the steps to improve code organization by creating regions for constants, variables, constructors, control events, and methods, as well as implementing specific methods for adding digits, deleting digits, adding decimals, toggling signs, and performing calculations. The document provides complete code examples for each method and event handler to demonstrate the refactoring process.

Uploaded by

Mouhib Mouhib
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 11

Object_Oriented_Programming in C #

Exercise: Refactoring the calculator application

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.

DeleteDigit(ref newValue, lblValue.Text);

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.

Calculate(out result, value1, value2, mathFunction);

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 AddDigit method


1. Add a method called AddDigit with a string return type and two string parameters
called labelText and buttonText to the Methods region.
#region Methods
private string AddDigit(string labelText, string buttonText)
{
}
#endregion
2. Locate the btnNumber_Click event and copy all code inside it except the first line
where the button is cast.
3. Paste the copied code into the AddDigit method body.
4. Replace all the occurrences of lblValue.Text with the labelText variable name.
5. Replace btn.Text with the buttonText variable.
6. Add a return statement returning the labelText variable.

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 btnNumber_Click event


1. Locate the btnNumber_Click event and delete all code inside it except the first line
where the button is cast.
2. Add a line of code where the result of the AddDigit method call is assigned to the
Text property of the lblValue label. Pass in the Text properties of the label and
button to the method.

The complete btnNumber_Click event code look like this:


private void btnNumber_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
lblValue.Text = AddDigit(lblValue.Text, btn.Text);
}
The DeleteDigit method
1. Add a method called DeleteDigit with a void return type and two string parameters
called newValue and value to the Methods region. The newValue parameter should
be defined with the ref keyword making it possible to pass in and return a value
through it.
private void DeleteDigit(ref string newValue, string value)
{
}
2. Locate the btnDelete_Click event and cut out all code inside it except the first and
last line of code.
3. Paste the copied code into the DeleteDigit method body.
4. Replace all occurrences of lblValue.Text with the value parameter.

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 btnDelete_Click event


1. Locate the btnDelete_Click event.
2. Add a line of code between the two remaining code lines calling the DeleteDigit
method passing in the newValue variable as the first parameter and the lblValue
label's text as the second parameter. You cannot assign the method call to the
label's Text property because it is declared as void but you can assign the value in
the ref variable.
The complete btnDelete_Click event code look like this:
private void btnDelete_Click(object sender, EventArgs e)
{
string newValue = noValue;
DeleteDigit(ref newValue, lblValue.Text);
lblValue.Text = newValue;
}

The AddDecimal method


1. Add a method called AddDecimal with a string return type and one string parameter
called value to the Methods region.
private string AddDecimal(string value) { }
2. Locate the btnDecimal_Click event and cut out all code inside it.
3. Paste the copied code into the AddDecimal method body.
4. Replace all occurrences of lblValue.Text with the value parameter.
5. Add a return statement returning the value variable.

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 btnDecimal_Click event


1. Locate the btnDelete_Click event.
2. Assign a call to the AddDecimal method to the Text property of the lblValue label
passing in the same Text property as a parameter to the method.

The complete btnDecimal_Click event code look like this:


private void btnDecimal_Click(object sender, EventArgs e)
{
lblValue.Text = AddDecimal(lblValue.Text);
}
The ToggleSign method
1. Add a method called ToggleSign with a string return type and one string parameter
called value to the Methods region.
private string ToggleSign(string value)
{
}
2. Locate the btnSign_Click event and cut out all code inside it.
3. Paste the cut code into the ToggleSign method body.
4. Replace all occurrences of lblValue.Text with the value parameter.
5. Add a return statement returning the value variable.

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 btnSign_Click event


1. Locate the btnSign_Click event.
2. Assign a call to the ToggleSign method to the Text property of the lblValue label
passing in the same Text property as a parameter to the method.

The complete btnSign_Click event code look like this:


private void btnSign_Click(object sender, EventArgs e)
{
lblValue.Text = ToggleSign(lblValue.Text);
}

The CanCalculate method


1. Add a method called CanCalculate with a bool return type and no parameters to the
Methods region.
private bool CanCalculate()
{
}
2. Locate the btnEquals_Click event and copy all code inside the first if-statement.
3. Paste the copied code into the CanCalculate method body as a return statement.
return lblFirstValue.Text.Equals(String.Empty) ||
lblMathFunction.Text.Equals(String.Empty) ||
lblValue.Text.Equals(String.Empty) ||
lblValue.Text.Equals(noValue);
The complete code for the CanCalculate method look like this:
private bool CanCalculate()
{
return lblFirstValue.Text.Equals(String.Empty) ||
lblMathFunction.Text.Equals(String.Empty) ||
lblValue.Text.Equals(String.Empty) ||
lblValue.Text.Equals(noValue);
}

The EndWithDecimalSign method


1. Add a method called EndWithDecimalSign with a string return type and one string
parameter called value to the Methods region.
private string EndWithDecimalSign(string value)
{
}
2. Locate the btnEquals_Click event and copy all code for the first check if the label's
text ends with a decimal.
var endsWithDecimalSign = lblFirstValue.Text.EndsWith(decimalSign);
int length = Convert.ToInt32(lblFirstValue.Text.Length);
if(endsWithDecimalSign)
lblFirstValue.Text = lblFirstValue.Text.Substring(0, length - 1);

3. Paste the copied code into the EndWithDecimalSign method body.


4. Replace all instances of lblFirstValue.Text with the value variable.
5. Add a return statement returning the value variable.

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 Calculate method


1. Add a method called Calculate to the Methods region with a void return type and
one double parameter called result declared with the out keyword making it possi-
ble to pass out but not in values through it. Add two other double parameters called
value1 and value2 and one string parameter called mathFunction. You must initial-
ize the result variable with the value 0d because an out parameter must always be
assigned a value.
private void Calculate(out double result, double value1, double
value2, string mathFunction)
{
result = 0d;
}
2. Locate the btnEquals_Click event and copy all calculation code.
3. Paste the copied code into the Calculate method body after the variable assignment.

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);

4. Now do the same for the lblValue label.


lblValue.Text = EndsWithDecimalSign(lblValue.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.

The complete btnEquals_Click event code look like this:


private void btnEquals_Click(object sender, EventArgs e)
{
if (CanCalculate()) return;

lblFirstValue.Text = EndsWithDecimalSign(lblFirstValue.Text);
lblValue.Text = EndsWithDecimalSign(lblValue.Text);

var value1 = Convert.ToDouble(lblFirstValue.Text);


var value2 = Convert.ToDouble(lblValue.Text);
var mathFunction = lblMathFunction.Text;
var result = 0d; // double = 0d

Calculate(out result, value1, value2, mathFunction);

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.

The complete btnSqrt_Click event code look like this:


private void btnSqrt_Click(object sender, EventArgs e)
{
bool hasSign = lblValue.Text.Contains(minusSign);
if (hasSign)
{
MessageBox.Show(
"Cannot calculate the square root of a negative number");
return; // Exit out of the event prematurely
}

lblValue.Text = EndsWithDecimalSign(lblValue.Text);

var value = Convert.ToDouble(lblValue.Text);


var result = Math.Sqrt(value);
lblValue.Text = result.ToString();
}

You might also like