1196 lines
35 KiB
Markdown
1196 lines
35 KiB
Markdown
# Create methods in C# console applications
|
||
|
||
Learn how to create methods for C# console applications. Use parameters and
|
||
return values to manipulate data across applications. Learn to use named and
|
||
optional arguments to simplify code.
|
||
|
||
## Introduction
|
||
|
||
The C# programming language allows you to create all sorts of robust
|
||
applications. Suppose you want to write code to perform operations on
|
||
unpredictable user input. You might want to add logic to handle incorrect input,
|
||
convert input into a workable format, and perform the correct operation. As your
|
||
applications grow larger in size, keeping track of your code can quickly become
|
||
a challenge.
|
||
|
||
Methods, also called functions, are a key part of keeping code structured,
|
||
efficient, and readable. A method is a modular unit of code, and a fundamental
|
||
programming concept. A method is often designed to perform a specific task and
|
||
contains code to execute that task. The name of a method should clearly reflect
|
||
its task, which improves code readability. Learning how to use methods will help
|
||
you build feature-rich applications more quickly.
|
||
|
||
In this module, you'll learn to create your own methods to perform specific
|
||
tasks. You'll learn how methods can simplify and shorten code, as well as keep
|
||
things organized and easy to find.
|
||
|
||
### Learning Objectives
|
||
|
||
In this module, you will:
|
||
|
||
- Create your first c sharp method
|
||
- Identify parts of code that can be modularized
|
||
- Use methods to organize code into specific tasks
|
||
|
||
---
|
||
|
||
### Understand the syntax of methods
|
||
|
||
You might already be familiar with some methods, such as `Console.WriteLine()`
|
||
or `random.Next()`. You might have appreciated how these methods simplify tasks
|
||
and allow you to build your code more easily. In this unit, you'll learn how to
|
||
create your own methods.
|
||
|
||
### How methods work
|
||
|
||
The process of developing a method begins with creating a method signature. The
|
||
method signature declares the method's return type, name, and input parameters.
|
||
For example, consider the following method signature:
|
||
|
||
```cs
|
||
void SayHello();
|
||
```
|
||
|
||
The method name is `SayHello`. Its return type is `void`, meaning the method
|
||
returns no data. However, methods can return a value of any data type, such as
|
||
`bool`, `int`, `double`, and arrays as well. Method parameters, if any, should
|
||
be included in the parenthesis `()`. Methods can accept multiple parameters of
|
||
any data type. In this example, the method has no parameters.
|
||
|
||
Before you can run a method, you need to add a definition. The method
|
||
definition uses brackets `{}` to contain the code that executes when the method
|
||
is called. For example:
|
||
|
||
```cs
|
||
void SayHello() {
|
||
Console.WriteLine("Hello World!");
|
||
}
|
||
```
|
||
|
||
Now the method will print `Hello World!` whenever it's called.
|
||
|
||
#### Calling a method
|
||
|
||
A method is called by using its name and including any required arguments.
|
||
Consider the following:
|
||
|
||
```cs
|
||
Console.Write("Input!");
|
||
```
|
||
|
||
The string `"Input!"` is the argument provided to the `Write` method.
|
||
|
||
A method can be called before or after its definition. For example, the
|
||
`SayHello` method can be defined and called using the following syntax:
|
||
|
||
```cs
|
||
SayHello();
|
||
|
||
void SayHello() {
|
||
Console.WriteLine("Hello World!");
|
||
}
|
||
```
|
||
|
||
Notice that it isn't necessary to have the method defined before you call it.
|
||
This flexibility allows you to organize your code as you see fit. It's common
|
||
to define all methods at the end of a program. For example:
|
||
|
||
```cs
|
||
int[] a = {1,2,3,4,5};
|
||
|
||
Console.WriteLine("Contents of Array:");
|
||
PrintArray();
|
||
|
||
void PrintArray() {
|
||
foreach (int x in a) {
|
||
Console.Write($"{x} ");
|
||
}
|
||
Console.WriteLine();
|
||
}
|
||
```
|
||
|
||
### Method execution
|
||
|
||
When you call a method, the code in the method body will be executed. This
|
||
means execution control is passed from the method caller to the method. Control
|
||
is returned to the caller after the method completes its execution. For example,
|
||
consider the following code:
|
||
|
||
```cs
|
||
Console.WriteLine("Before calling a method");
|
||
SayHello();
|
||
Console.WriteLine("After calling a method");
|
||
|
||
void SayHello() {
|
||
Console.WriteLine("Hello World!");
|
||
}
|
||
```
|
||
|
||
This code displays the following output:
|
||
|
||
```txt
|
||
Before calling a method
|
||
Hello World!
|
||
After calling a method
|
||
```
|
||
|
||
Once a method is defined, it can be called anytime, as many times as you need
|
||
to use it. You can use methods inside of `if-else` statements, `for`-loops,
|
||
`switch` statements, even to initialize variables, and so much more!
|
||
|
||
#### Best practices
|
||
|
||
When choosing a method name, it's important to keep the name concise and make
|
||
it clear what task the method performs. Method names should be Pascal case and
|
||
generally shouldn't start with digits. Names for parameters should describe
|
||
what kind of information the parameter represents. Consider the following
|
||
method signatures:
|
||
|
||
```cs
|
||
void ShowData(string a, int b, int c);
|
||
void DisplayDate(string month, int day, int year);
|
||
```
|
||
|
||
The second method describes what kind of data is displayed and provides
|
||
descriptive names for parameters.
|
||
|
||
Now that you have the basics down, you're ready to begin writing your own
|
||
methods!
|
||
|
||
---
|
||
|
||
## Exercise
|
||
|
||
### Create your first method
|
||
|
||
Typically, a method is created to perform a specific task. In this exercise,
|
||
you'll create a method that generates and displays five random numbers. Let's
|
||
get started!
|
||
|
||
#### Create a method to display random numbers
|
||
|
||
To create a method, first create a method signature and then add the method
|
||
body. To create the method signature, you declare the return type, method name,
|
||
and parameters. Create the method body by using brackets `{}` that contain the
|
||
code.
|
||
|
||
Enter the following code into the Visual Studio Code editor:
|
||
|
||
```cs
|
||
void DisplayRandomNumbers();
|
||
```
|
||
|
||
In this case, the method just needs to generate and display information, so the
|
||
return type is `void`. For now, you don't need to include any parameters.
|
||
|
||
To create the method body, remove the semicolon `;` and update your code to the
|
||
following:
|
||
|
||
```cs
|
||
void DisplayRandomNumbers() {
|
||
Random random = new Random();
|
||
}
|
||
```
|
||
|
||
Here, you create a `Random` object that is used to generate the numbers.
|
||
|
||
To display five random integers, add a `for` loop to your method:
|
||
|
||
```cs
|
||
void DisplayRandomNumbers() {
|
||
Random random = new Random();
|
||
|
||
for (int i = 0; i < 5; i++) {
|
||
Console.Write($"{random.Next(1, 100)} ");
|
||
}
|
||
}
|
||
```
|
||
|
||
In this code, you generate a number between 1 and 99 (inclusive). You also add
|
||
a space after the number is printed. Next, you'll display a new line before the
|
||
method terminates.
|
||
|
||
Update your method with the following code:
|
||
|
||
```cs
|
||
void DisplayRandomNumbers() {
|
||
Random random = new Random();
|
||
for (int i = 0; i < 5; i++) {
|
||
Console.Write($"{random.Next(1, 100)} ");
|
||
}
|
||
Console.WriteLine();
|
||
}
|
||
```
|
||
|
||
Now your method will add a new line after displaying the numbers.
|
||
|
||
#### Call your method
|
||
|
||
Enter a new blank code line above the `DisplayRandomNumbers` method.
|
||
|
||
Enter the following code on the new blank code line:
|
||
|
||
```cs
|
||
Console.WriteLine("Generating random numbers:");
|
||
DisplayRandomNumbers();
|
||
```
|
||
|
||
Compare your code with the following to ensure it's correct:
|
||
|
||
```cs
|
||
Console.WriteLine("Generating random numbers:");
|
||
DisplayRandomNumbers();
|
||
|
||
void DisplayRandomNumbers() {
|
||
Random random = new Random();
|
||
|
||
for (int i = 0; i < 5; i++) {
|
||
Console.Write($"{random.Next(1, 100)} ");
|
||
}
|
||
|
||
Console.WriteLine();
|
||
}
|
||
```
|
||
|
||
Notice how using a method makes the code easy to understand. Rather than
|
||
spending time trying to decipher the `for` loop on its own, you can quickly
|
||
read the method name to learn that this code displays random numbers.
|
||
|
||
### Check Your Work
|
||
|
||
In this task, you'll run your application from the Integrated Terminal and
|
||
verify your code is working correctly. Let's get started.
|
||
|
||
At the Terminal command prompt, enter `dotnet run`
|
||
|
||
To verify that your code is working as expected, check that the output of your
|
||
application is similar to the following output (taking into account the
|
||
randomly generated numbers):
|
||
|
||
```cs
|
||
17 29 46 36 3
|
||
```
|
||
|
||
- [Program.cs](./methods/Program.cs)
|
||
|
||
If your code displays different results, you'll need to review your code to
|
||
find your error and make updates. Run the code again to see if you've fixed the
|
||
problem. Continue updating and running your code until your code produces the
|
||
expected results.
|
||
|
||
### Recap
|
||
|
||
Here's what you've learned about methods so far:
|
||
|
||
- Create a method by declaring the return type, name, input parameters, and method body.
|
||
- Method names should clearly reflect the task the method performs.
|
||
- Use a method by calling its name and including parentheses ().
|
||
|
||
---
|
||
|
||
## Exercise
|
||
|
||
### Create reusable methods
|
||
|
||
As you develop applications, you might find yourself writing code to do the
|
||
same thing over and over again. Instead of writing duplicate code, using a
|
||
method to perform the same task shortens your code and helps you develop
|
||
applications faster. In this exercise, you'll identify repeated code and
|
||
replace it with a reusable method. Let's get started!
|
||
|
||
#### Identify duplicated code
|
||
|
||
In this task, you'll take a look at an application that tracks medication times
|
||
across different time zones. The user enters their current time zone and their
|
||
destination time zone. Their medication schedule is displayed and then adjusted
|
||
for the new time zone.
|
||
|
||
In the code editor, delete any existing code from the previous exercises.
|
||
|
||
Copy and paste the following code:
|
||
|
||
```cs
|
||
using System;
|
||
|
||
int[] times = {800, 1200, 1600, 2000};
|
||
int diff = 0;
|
||
|
||
Console.WriteLine("Enter current GMT");
|
||
int currentGMT = Convert.ToInt32(Console.ReadLine());
|
||
|
||
Console.WriteLine("Current Medicine Schedule:");
|
||
|
||
/* Format and display medicine times */
|
||
foreach (int val in times) {
|
||
string time = val.ToString();
|
||
int len = time.Length;
|
||
if (len >= 3) {
|
||
time = time.Insert(len - 2, ":");
|
||
}
|
||
else if (len == 2) {
|
||
time = time.Insert(0, "0:");
|
||
} else {
|
||
time = time.Insert(0, "0:0");
|
||
}
|
||
Console.Write($"{time} ");
|
||
}
|
||
|
||
Console.WriteLine();
|
||
|
||
Console.WriteLine("Enter new GMT");
|
||
int newGMT = Convert.ToInt32(Console.ReadLine());
|
||
|
||
if (Math.Abs(newGMT) > 12 || Math.Abs(currentGMT) > 12) {
|
||
Console.WriteLine("Invalid GMT");
|
||
} else if (newGMT <= 0 && currentGMT <= 0 || newGMT >= 0 && currentGMT >= 0) {
|
||
diff = 100 * (Math.Abs(newGMT) - Math.Abs(currentGMT));
|
||
/* Adjust the times by adding the difference, keeping the value within 24 hours */
|
||
for (int i = 0; i < times.Length; i++) {
|
||
times[i] = ((times[i] + diff)) % 2400;
|
||
}
|
||
} else {
|
||
diff = 100 * (Math.Abs(newGMT) + Math.Abs(currentGMT));
|
||
/* Adjust the times by adding the difference, keeping the value within 24 hours */
|
||
for (int i = 0; i < times.Length; i++) {
|
||
times[i] = ((times[i] + diff)) % 2400;
|
||
}
|
||
}
|
||
|
||
Console.WriteLine("New Medicine Schedule:");
|
||
|
||
/* Format and display medicine times */
|
||
foreach (int val in times) {
|
||
string time = val.ToString();
|
||
int len = time.Length;
|
||
if (len >= 3) {
|
||
time = time.Insert(len - 2, ":");
|
||
} else if (len == 2) {
|
||
time = time.Insert(0, "0:");
|
||
} else {
|
||
time = time.Insert(0, "0:0");
|
||
}
|
||
Console.Write($"{time} ");
|
||
}
|
||
|
||
Console.WriteLine();
|
||
```
|
||
|
||
Notice that there's several `for`-loops that are repeated with identical code.
|
||
|
||
There are two `foreach` loops that format and display the medicine times. There
|
||
are another two `for` loops that adjust the times according to the time zone
|
||
difference.
|
||
|
||
As you write code, you might find yourself repeating blocks of code to do the
|
||
same task. That's a perfect opportunity to consolidate your code by using a
|
||
method to perform the task instead. Let's practice!
|
||
|
||
#### Create methods to perform the repeated tasks
|
||
|
||
Now that you've identified repeated code, you can create a method to contain
|
||
the code and remove the duplicates. Using methods has the added bonus of
|
||
shortening your code and improving readability! The `foreach` loops format and
|
||
display the time values, so you can give the method a name that clearly
|
||
reflects that task. You can do the same with the `for` loop that adjusts the
|
||
times. Let's get started!
|
||
|
||
Enter a new blank code line at the end of the previous code.
|
||
|
||
On the new blank code line, create a method signature by entering the following
|
||
code:
|
||
|
||
```cs
|
||
void DisplayTimes() {
|
||
|
||
}
|
||
```
|
||
|
||
To define the method body, update the DisplayTimes method by copy and pasting
|
||
the foreach block as follows:
|
||
|
||
```cs
|
||
void DisplayTimes() {
|
||
/* Format and display medicine times */
|
||
foreach (int val in times) {
|
||
string time = val.ToString();
|
||
int len = time.Length;
|
||
if (len >= 3) {
|
||
time = time.Insert(len - 2, ":");
|
||
} else if (len == 2) {
|
||
time = time.Insert(0, "0:");
|
||
} else {
|
||
time = time.Insert(0, "0:0");
|
||
}
|
||
Console.Write($"{time} ");
|
||
}
|
||
|
||
Console.WriteLine();
|
||
}
|
||
```
|
||
|
||
In this method, you include the call to `Console.WriteLine` at the end to
|
||
append a new line after the times are displayed. Next, you'll create another
|
||
method to adjust the times according to the time zone difference.
|
||
|
||
Enter a new blank code line at the end of the previous code.
|
||
|
||
On the new blank code line, create a method signature by entering the following
|
||
code:
|
||
|
||
```cs
|
||
void AdjustTimes() {
|
||
|
||
}
|
||
```
|
||
|
||
Update the `AdjustTimes` method by copy and pasting the `for` loop as follows:
|
||
|
||
```cs
|
||
void AdjustTimes() {
|
||
/* Adjust the times by adding the difference, keeping the value within 24 hours */
|
||
for (int i = 0; i < times.Length; i++) {
|
||
times[i] = ((times[i] + diff)) % 2400;
|
||
}
|
||
}
|
||
```
|
||
|
||
#### Step 3: Call the methods
|
||
|
||
In this task, you'll delete the repeated blocks of code and replace them with
|
||
calls to the methods you created.
|
||
|
||
Locate the first instance of the repeated `foreach` loop under the comment
|
||
"Format and display medicine times":
|
||
|
||
```cs
|
||
Console.WriteLine("Current Medicine Schedule:");
|
||
|
||
/* Format and display medicine times */
|
||
foreach (int val in times) {
|
||
...
|
||
}
|
||
|
||
Console.WriteLine();
|
||
|
||
Console.WriteLine("Enter new GMT");
|
||
```
|
||
|
||
Replace the code you identified with a call to the `DisplayTimes` method. The
|
||
replacement should result in the following code:
|
||
|
||
```cs
|
||
Console.WriteLine("Current Medicine Schedule:");
|
||
DisplayTimes();
|
||
|
||
Console.WriteLine("Enter new GMT");
|
||
```
|
||
|
||
Next, you'll replace the second instance of the repeated code.
|
||
|
||
Locate the second instance of the `foreach` loop under the comment "Format and
|
||
display medicine times":
|
||
|
||
```cs
|
||
Console.WriteLine("New Medicine Schedule:");
|
||
|
||
/* Format and display medicine times */
|
||
foreach (int val in times) {
|
||
...
|
||
}
|
||
|
||
Console.WriteLine();
|
||
```
|
||
|
||
Replace the code you identified with a call to the `DisplayTimes` method. The
|
||
replacement should result in the following code:
|
||
|
||
```cs
|
||
Console.WriteLine("New Medicine Schedule:");
|
||
DisplayTimes();
|
||
```
|
||
|
||
Notice how using a method in place of a large block of code provides more
|
||
clarity and makes the code easier to understand. Let's do the same with the
|
||
`AdjustTimes` method you created.
|
||
|
||
Locate the following code with the duplicated `for`-loops:
|
||
|
||
```cs
|
||
else if (newGMT <= 0 && currentGMT <= 0 || newGMT >= 0 && currentGMT >= 0) {
|
||
diff = 100 * (Math.Abs(newGMT) - Math.Abs(currentGMT));
|
||
/* Adjust the times by adding the difference, keeping the value within 24 hours */
|
||
for (int i = 0; i < times.Length; i++) {
|
||
times[i] = ((times[i] + diff)) % 2400;
|
||
}
|
||
} else {
|
||
diff = 100 * (Math.Abs(newGMT) + Math.Abs(currentGMT));
|
||
|
||
/* Adjust the times by adding the difference, keeping the value within 24 hours */
|
||
for (int i = 0; i < times.Length; i++) {
|
||
times[i] = ((times[i] + diff)) % 2400;
|
||
}
|
||
}
|
||
```
|
||
|
||
Replace the instances of repeated code under the comment "Adjust the times by
|
||
adding the difference" with calls to your `AdjustTimes` method. The replacement
|
||
should result in the following code:
|
||
|
||
```cs
|
||
else if (newGMT <= 0 && currentGMT <= 0 || newGMT >= 0 && currentGMT >= 0) {
|
||
diff = 100 * (Math.Abs(newGMT) - Math.Abs(currentGMT));
|
||
AdjustTimes();
|
||
} else {
|
||
diff = 100 * (Math.Abs(newGMT) + Math.Abs(currentGMT));
|
||
AdjustTimes();
|
||
}
|
||
```
|
||
|
||
Now all of the duplicated code has been replaced by your new method. Notice how
|
||
much more readable and concise your code looks!
|
||
|
||
### Check Your Work
|
||
|
||
In this task, you'll run your application from the Integrated Terminal and
|
||
verify your code is working correctly. Let's get started.
|
||
|
||
Compare your code with the following to ensure it's correct:
|
||
|
||
```cs
|
||
int[] times = {800, 1200, 1600, 2000};
|
||
int diff = 0;
|
||
|
||
Console.WriteLine("Enter current GMT");
|
||
int currentGMT = Convert.ToInt32(Console.ReadLine());
|
||
|
||
Console.WriteLine("Current Medicine Schedule:");
|
||
DisplayTimes();
|
||
|
||
Console.WriteLine("Enter new GMT");
|
||
int newGMT = Convert.ToInt32(Console.ReadLine());
|
||
|
||
if (Math.Abs(newGMT) > 12 || Math.Abs(currentGMT) > 12) {
|
||
Console.WriteLine("Invalid GMT");
|
||
} else if (newGMT <= 0 && currentGMT <= 0 || newGMT >= 0 && currentGMT >= 0) {
|
||
diff = 100 * (Math.Abs(newGMT) - Math.Abs(currentGMT));
|
||
AdjustTimes();
|
||
} else {
|
||
diff = 100 * (Math.Abs(newGMT) + Math.Abs(currentGMT));
|
||
AdjustTimes();
|
||
}
|
||
|
||
Console.WriteLine("New Medicine Schedule:");
|
||
DisplayTimes();
|
||
|
||
void DisplayTimes() {
|
||
/* Format and display medicine times */
|
||
foreach (int val in times) {
|
||
string time = val.ToString();
|
||
int len = time.Length;
|
||
if (len >= 3) {
|
||
time = time.Insert(len - 2, ":");
|
||
} else if (len == 2) {
|
||
time = time.Insert(0, "0:");
|
||
} else {
|
||
time = time.Insert(0, "0:0");
|
||
}
|
||
Console.Write($"{time} ");
|
||
}
|
||
Console.WriteLine();
|
||
}
|
||
|
||
void AdjustTimes() {
|
||
/* Adjust the times by adding the difference, keeping the value within 24 hours */
|
||
for (int i = 0; i < times.Length; i++) {
|
||
times[i] = ((times[i] + diff)) % 2400;
|
||
}
|
||
}
|
||
```
|
||
|
||
At the Terminal command prompt, enter `dotnet run`
|
||
|
||
Enter -6 and +6 for the GMT prompts.
|
||
|
||
Verify that your code produces the following output:
|
||
|
||
```txt
|
||
Enter current GMT
|
||
-6
|
||
Current Medicine Schedule:
|
||
8:00 12:00 16:00 20:00
|
||
Enter new GMT
|
||
+6
|
||
New Medicine Schedule:
|
||
20:00 0:00 4:00 8:00
|
||
```
|
||
|
||
If your code displays different results, you'll need to review your code to
|
||
find your error and make updates. Run the code again to see if you've fixed the
|
||
problem. Continue updating and running your code until your code produces the
|
||
expected results.
|
||
|
||
- [Program.cs](./reusable_methods/Program.cs)
|
||
|
||
---
|
||
|
||
## Exercise
|
||
|
||
### Build code with methods
|
||
|
||
Methods are useful for organizing code, reusing code, and for tackling problems
|
||
efficiently. You can think of a method like a black box that takes input,
|
||
performs the named task, and returns output. With this assumption, you can
|
||
quickly structure programs just by naming your tasks as methods, and then
|
||
filling in the logic after you've identified all of the necessary tasks.
|
||
|
||
When you use plain language to describe steps in code, without strictly
|
||
adhering to syntax rules, you're using "pseudo-code". Combining methods and
|
||
pseudo-code is a great way to quickly power through any challenging programming
|
||
task.
|
||
|
||
### Use methods to structure code
|
||
|
||
Suppose you're a candidate in a coding interview. The interviewer wants you to
|
||
write a program that checks whether an IPv4 address is valid or invalid. You're
|
||
given the following rules:
|
||
|
||
- A valid IPv4 address consists of four numbers separated by dots
|
||
- Each number must not contain leading zeroes
|
||
- Each number must range from 0 to 255
|
||
|
||
1.1.1.1 and 255.255.255.255 are examples of valid IP addresses.
|
||
|
||
The IPv4 address is provided as a string. You can assume that it only consists
|
||
of digits and dots (there are no letters in the string provided).
|
||
|
||
How would you approach this task?
|
||
|
||
> Note
|
||
> Even if you aren't familiar with IP addresses, don't worry! You can still
|
||
complete the code in this exercise by following the steps.
|
||
|
||
#### Break down the problem
|
||
|
||
In this task, you'll identify the steps needed to solve the problem. If you look
|
||
closely at the rules, you might realize that it only takes three steps to
|
||
determine whether or not an IPv4 address is valid.
|
||
|
||
Enter the following pseudo-code into the Editor:
|
||
|
||
```cs
|
||
/*
|
||
if ipAddress consists of 4 numbers
|
||
and
|
||
if each ipAddress number has no leading zeroes
|
||
and
|
||
if each ipAddress number is in range 0 - 255
|
||
|
||
then ipAddress is valid
|
||
|
||
else ipAddress is invalid
|
||
*/
|
||
```
|
||
|
||
Pseudo-code is a great way to begin tackling any problem. Using this comment
|
||
block, you bridge the gap between the prompt rules and the program code,
|
||
clarifying the major tasks your code will perform. Pseudo-code doesn't need to
|
||
be functional or adhere to syntax rules, however, it should be a clear
|
||
explanation of what the code will do. Now let's turn this into real code!
|
||
|
||
Enter a new blank code line, then type the following code in the Editor:
|
||
|
||
```cs
|
||
if (ValidateLength() && ValidateZeroes() && ValidateRange()) {
|
||
Console.WriteLine($"ip is a valid IPv4 address");
|
||
} else {
|
||
Console.WriteLine($"ip is an invalid IPv4 address");
|
||
}
|
||
```
|
||
|
||
In this step, you transform the `if` statements from your pseudo-code into
|
||
callable methods and output the results. Don't worry about defining the methods
|
||
yet; you can assume that each method performs the task its name describes.
|
||
You'll fix the compilation errors and create the method logic soon, but focus
|
||
on the big picture for now. When you begin working on a new program, focusing
|
||
on the overall design helps you stay organized and develop your application
|
||
faster.
|
||
|
||
Enter a new blank code line below the existing code, then type the following
|
||
code in the Editor:
|
||
|
||
```cs
|
||
void ValidateLength() {}
|
||
void ValidateZeroes() {}
|
||
void ValidateRange() {}
|
||
```
|
||
|
||
Notice how using placeholder methods allowed you to quickly approach the problem
|
||
and structure your code to develop the solution. Now that you have a structured
|
||
plan in place, you can continue to solve the problem by filling in the code
|
||
piece by piece.
|
||
|
||
#### Develop your solution
|
||
|
||
Now that you have all the placeholder methods needed to solve the problem, you
|
||
can begin to focus on the details of your solution. Keep in mind that the input
|
||
format of the IPv4 address will be a string consisting of digits separated by
|
||
dots. Let's get stared!
|
||
|
||
At the beginning of your program, create variables to store the input and
|
||
validation statuses:
|
||
|
||
```cs
|
||
string ipv4Input = "107.31.1.5";
|
||
bool validLength = false;
|
||
bool validZeroes = false;
|
||
bool validRange = false;
|
||
```
|
||
|
||
Update your solution code to use the validation variables as follows:
|
||
|
||
```cs
|
||
ValidateLength();
|
||
ValidateZeroes();
|
||
ValidateRange();
|
||
|
||
if (validLength && validZeroes && validRange) {
|
||
Console.WriteLine($"ip is a valid IPv4 address");
|
||
} else {
|
||
Console.WriteLine($"ip is an invalid IPv4 address");
|
||
}
|
||
```
|
||
|
||
Update the `ValidateLength` method as follows:
|
||
|
||
```cs
|
||
void ValidateLength() {
|
||
string[] address = ipv4Input.Split(".");
|
||
validLength = address.Length == 4;
|
||
};
|
||
```
|
||
|
||
The first rule states that the IPv4 address needs to have four numbers. So in
|
||
this code, you use `string.Split` to separate the digits and check that there are
|
||
four of them.
|
||
|
||
Update the `ValidateZeroes` method as follows:
|
||
|
||
```cs
|
||
void ValidateZeroes() {
|
||
string[] address = ipv4Input.Split(".");
|
||
foreach (string number in address) {
|
||
if (number.Length > 1 && number.StartsWith("0")) {
|
||
validZeroes = false;
|
||
}
|
||
}
|
||
validZeroes = true;
|
||
}
|
||
```
|
||
|
||
Take a moment to consider how the rule translates to code.
|
||
|
||
The second rule states that the numbers in the IPv4 address must not contain
|
||
leading zeroes. So the method needs to check numbers for leading zeroes while
|
||
accepting `0` as a valid number. If all the numbers have valid zeroes,
|
||
`validZeroes` should be equal to `true`, and `false` otherwise. So in this code,
|
||
you check that each number with more than one digit does not begin with a zero.
|
||
|
||
If you look closely, you'll notice that `validZeroes` is set to true after the
|
||
foreach loop completes. However, you only want to set `validZeroes` to `true`
|
||
if no leading zeroes are found. You could correct this bug by setting
|
||
`validZeroes = true` before the `foreach` loop runs. However, you can also
|
||
correct this bug using a return statement.
|
||
|
||
Update your code to the following:
|
||
|
||
```cs
|
||
foreach (string number in address) {
|
||
if (number.Length > 1 && number.StartsWith("0")) {
|
||
validZeroes = false;
|
||
return;
|
||
}
|
||
}
|
||
```
|
||
|
||
The **return** statement terminates execution of the method and returns control
|
||
to the method caller. Adding a `return` statement after `validZeroes = false`
|
||
terminates the method after the first invalid zero is found. If no invalid zero
|
||
is found, the method will terminate after setting `validZeroes` to `true`. Let's
|
||
move on to the next method.
|
||
|
||
Update the `ValidateRange` method as follows:
|
||
|
||
```cs
|
||
void ValidateRange() {
|
||
string[] address = ipv4Input.Split(".");
|
||
|
||
foreach (string number in address) {
|
||
int value = int.Parse(number);
|
||
if (value < 0 || value > 255) {
|
||
validRange = false;
|
||
return;
|
||
}
|
||
}
|
||
validRange = true;
|
||
}
|
||
```
|
||
|
||
The third rule states that each number in the IPv4 address must range from 0 to
|
||
255. So in this code, you check that each number is less than 255, and if not,
|
||
terminate execution after setting `validRange` to `false`. Since the input
|
||
string only contains digits and dots, you don't need to check for negative
|
||
numbers.
|
||
|
||
However, there might be a case where no digits are present between dots. For
|
||
example, "255...255". In this case, `string.Split(".")` would return empty
|
||
entries, causing `int.Parse` to fail. You can prevent this by specifying
|
||
`StringSplitOptions`.
|
||
|
||
Update your code as follows:
|
||
|
||
```cs
|
||
string[] address = ipv4Input.Split(".", StringSplitOptions.RemoveEmptyEntries);
|
||
```
|
||
|
||
Using `StringSplitOptions.RemoveEmptyEntries` omits empty entries from the
|
||
`address` array and prevent attempts to parse empty strings.
|
||
|
||
#### Complete your solution
|
||
|
||
Now that you have all the methods completed to validate an IP address, it's
|
||
time to revisit your initial solution. In this task, you'll add more input
|
||
values and prepare to test your code.
|
||
|
||
Locate the following code you wrote earlier in the program:
|
||
|
||
```cs
|
||
string ipv4Input = "107.31.1.5";
|
||
```
|
||
|
||
Update the code as follows:
|
||

|
||
```cs
|
||
string[] ipv4Input = {"107.31.1.5", "255.0.0.255", "555..0.555", "255...255"};
|
||
```
|
||
|
||
When developing a solution, it is important to test your code with different
|
||
input cases. In this code, you provide a decent range of test values. Now that
|
||
you've updated your test input, you'll need to update your code to use the new
|
||
values. Since the values are in an array, you'll need to update your code to
|
||
test each one using a loop.
|
||
|
||
Update your code as follows:
|
||
|
||
```cs
|
||
foreach (string ip in ipv4Input) {
|
||
ValidateLength();
|
||
ValidateZeroes();
|
||
ValidateRange();
|
||
|
||
if (validLength && validZeroes && validRange) {
|
||
Console.WriteLine($"{ip} is a valid IPv4 address");
|
||
} else {
|
||
Console.WriteLine($"{ip} is an invalid IPv4 address");
|
||
}
|
||
}
|
||
```
|
||
|
||
Lastly, you need to fix the input data each method uses since you updated
|
||
`ipv4Input` from a string to an array. Since each method uses `string.Split`,
|
||
you can declare a variable to store the result of `string.Split` and use it in
|
||
each method instead.
|
||
|
||
Add a variable to store the current IPv4 address that each method will
|
||
reference:
|
||
|
||
```cs
|
||
string[] ipv4Input = {"107.31.1.5", "255.0.0.255", "555..0.555", "255...255"};
|
||
string[] address;
|
||
bool validLength = false;
|
||
bool validZeroes = false;
|
||
bool validRange = false;
|
||
```
|
||
|
||
Initialize `address` using `string.Split` as follows:
|
||
|
||
```cs
|
||
foreach (string ip in ipv4Input) {
|
||
address = ip.Split(".", StringSplitOptions.RemoveEmptyEntries);
|
||
```
|
||
Remove references to `string.Split` from each of the validation methods so that
|
||
they use the global `address` variable instead. For example:
|
||
|
||
```cs
|
||
void ValidateLength() {
|
||
validLength = address.Length == 4;
|
||
};
|
||
```
|
||
|
||
### Check Your Work
|
||
|
||
In this task, you'll run your application from the Integrated Terminal and
|
||
verify your code is working correctly. Let's get started.
|
||
|
||
Compare your code with the following to ensure it is correct:
|
||
|
||
```cs
|
||
string[] ipv4Input = {"107.31.1.5", "255.0.0.255", "555..0.555", "255...255"};
|
||
string[] address;
|
||
bool validLength = false;
|
||
bool validZeroes = false;
|
||
bool validRange = false;
|
||
|
||
foreach (string ip in ipv4Input) {
|
||
address = ip.Split(".", StringSplitOptions.RemoveEmptyEntries);
|
||
ValidateLength();
|
||
ValidateZeroes();
|
||
ValidateRange();
|
||
if (validLength && validZeroes && validRange) {
|
||
Console.WriteLine($"{ip} is a valid IPv4 address");
|
||
} else {
|
||
Console.WriteLine($"{ip} is an invalid IPv4 address");
|
||
}
|
||
}
|
||
|
||
void ValidateLength() {
|
||
validLength = address.Length == 4;
|
||
};
|
||
|
||
void ValidateZeroes() {
|
||
foreach (string number in address) {
|
||
if (number.Length > 1 && number.StartsWith("0")) {
|
||
validZeroes = false;
|
||
return;
|
||
}
|
||
}
|
||
validZeroes = true;
|
||
}
|
||
|
||
void ValidateRange() {
|
||
foreach (string number in address) {
|
||
int value = int.Parse(number);
|
||
if (value < 0 || value > 255) {
|
||
validRange = false;
|
||
return;
|
||
}
|
||
}
|
||
validRange = true;
|
||
}
|
||
```
|
||
|
||
At the Terminal command prompt, enter `dotnet run`
|
||
|
||
Verify that your code produces the following output:
|
||
|
||
```txt
|
||
107.31.1.5 is a valid IPv4 address
|
||
255.0.0.255 is a valid IPv4 address
|
||
555..0.555 is an invalid IPv4 address
|
||
255...255 is an invalid IPv4 address
|
||
```
|
||
|
||
If your code displays different results, you'll need to review your code to
|
||
find your error and make updates. Run the code again to see if you've fixed the
|
||
problem. Continue updating and running your code until your code produces the
|
||
expected results.
|
||
|
||
- [Program.cs](./ipv4/Program.cs)
|
||
|
||
### Recap
|
||
|
||
Here's what you've learned about using methods so far:
|
||
|
||
- Methods can be used to quickly structure applications
|
||
- The `return` keyword can be used to terminate method execution
|
||
- Each step of a problem can often be translated into its own method
|
||
- Use methods to solve small problems to build up your solution
|
||
|
||
---
|
||
|
||
## Exercise - Complete the challenge to create a reusable method
|
||
|
||
Code challenges reinforce what you've learned, and help you gain some
|
||
confidence before continuing on.
|
||
|
||
The focus of this challenge is to modify code so that it is reusable and can be
|
||
executed at any time.
|
||
|
||
### Tell a fortune
|
||
|
||
You're helping to develop a massive multiplayer role-playing game. Each player
|
||
has a luck stat that can affect their odds of finding rare treasure. Each day,
|
||
a player can speak to an in-game fortune teller that reveals whether their luck
|
||
stat is high, low, or neutral.
|
||
|
||
The game currently has code to generate a player's fortune, but it isn't
|
||
reusable. Your task is to create a `tellFortune` method that can be called at
|
||
any time, and replace the existing logic with a call to your method.
|
||
|
||
In this challenge, you're given some starting code. You must decide how to
|
||
create and call the `tellFortune` method.
|
||
|
||
#### Code challenge: create a reusable method
|
||
|
||
In the code that you start with, there's a generic text array, followed by goo
|
||
d, bad, and neutral text arrays. Depending on the value of `luck`, one of the
|
||
arrays is selected and displayed alongside the generic text.
|
||
|
||
Your challenge is to create a reusable method that prints a player's fortune at
|
||
any time. The method should contain the logic that is already present in the
|
||
code provided.
|
||
|
||
Copy and paste the following code into the Editor:
|
||
|
||
```cs
|
||
Random random = new Random();
|
||
int luck = random.Next(100);
|
||
|
||
string[] text = {
|
||
"You have much to",
|
||
"Today is a day to",
|
||
"Whatever work you do",
|
||
"This is an ideal time to"
|
||
};
|
||
string[] good = {
|
||
"look forward to.",
|
||
"try new things!",
|
||
"is likely to succeed.",
|
||
"accomplish your dreams!"
|
||
};
|
||
string[] bad = {
|
||
"fear.",
|
||
"avoid major decisions.",
|
||
"may have unexpected outcomes.",
|
||
"re-evaluate your life."
|
||
};
|
||
string[] neutral = {
|
||
"appreciate.",
|
||
"enjoy time with friends.",
|
||
"should align with your values.",
|
||
"get in tune with nature."
|
||
};
|
||
|
||
Console.WriteLine("A fortune teller whispers the following words:");
|
||
string[] fortune = (luck > 75 ? good : (luck < 25 ? bad : neutral));
|
||
for (int i = 0; i < 4; i++) {
|
||
Console.Write($"{text[i]} {fortune[i]} ");
|
||
}
|
||
```
|
||
|
||
Update the code to use a method to display the fortune.
|
||
|
||
Use what you've learned about creating and calling methods to complete the
|
||
update.
|
||
|
||
Test your code by changing the value of `luck` and calling the method again.
|
||
|
||
Verify that your code produces one of the following messages:
|
||
|
||
```txt
|
||
A fortune teller whispers the following words:
|
||
You have much to look forward to. Today is a day to try new things! Whatever work you do is likely to succeed. This is an ideal time to accomplish your dreams!
|
||
```
|
||
|
||
```txt
|
||
A fortune teller whispers the following words:
|
||
You have much to appreciate. Today is a day to enjoy time with friends. Whatever work you do should align with your values. This is an ideal time to get in tune with nature.
|
||
```
|
||
|
||
```txt
|
||
A fortune teller whispers the following words:
|
||
You have much to fear. Today is a day to avoid major decisions. Whatever work you do may have unexpected outcomes. This is an ideal time to re-evaluate your life.
|
||
```
|
||
|
||
Whether you get stuck and need to peek at the solution or you finish
|
||
successfully, continue on to view a solution to this challenge.
|
||
|
||
---
|
||
|
||
### Review the solution to create a reusable method
|
||
|
||
The following code is one possible solution for the challenge from the previous
|
||
unit.
|
||
|
||
```cs
|
||
Random random = new Random();
|
||
int luck = random.Next(100);
|
||
|
||
string[] text = {
|
||
"You have much to",
|
||
"Today is a day to",
|
||
"Whatever work you do",
|
||
"This is an ideal time to"
|
||
};
|
||
string[] good = {
|
||
"look forward to.",
|
||
"try new things!",
|
||
"is likely to succeed.",
|
||
"accomplish your dreams!"
|
||
};
|
||
string[] bad = {
|
||
"fear.",
|
||
"avoid major decisions.",
|
||
"may have unexpected outcomes.",
|
||
"re-evaluate your life."
|
||
};
|
||
string[] neutral = {
|
||
"appreciate.",
|
||
"enjoy time with friends.",
|
||
"should align with your values.",
|
||
"get in tune with nature."
|
||
};
|
||
|
||
tell_fortune();
|
||
|
||
void tell_fortune() {
|
||
Console.WriteLine("A fortune teller whispers the following words:");
|
||
string[] fortune = (luck > 75 ? good : (luck < 25 ? bad : neutral));
|
||
for (int i = 0; i < 4; i++) {
|
||
Console.Write($"{text[i]} {fortune[i]} ");
|
||
}
|
||
}
|
||
```
|
||
|
||
This code is just "one possible solution" because you might have added line
|
||
feeds in different spots or you might have formatted the code differently.
|
||
|
||
Regardless of minor code differences, when you run the code, you should see one
|
||
of the following output messages:
|
||
|
||
```txt
|
||
A fortune teller whispers the following words:
|
||
You have much to look forward to. Today is a day to try new things! Whatever work you do is likely to succeed. This is an ideal time to accomplish your dreams!
|
||
```
|
||
|
||
```txt
|
||
A fortune teller whispers the following words:
|
||
You have much to appreciate. Today is a day to enjoy time with friends. Whatever work you do should align with your values. This is an ideal time to get in tune with nature.
|
||
```
|
||
|
||
```txt
|
||
A fortune teller whispers the following words:
|
||
You have much to fear. Today is a day to avoid major decisions. Whatever work you do may have unexpected outcomes. This is an ideal time to re-evaluate your life.
|
||
```
|
||
|
||
The output should be dependent on the value of the `luck` variable.
|
||
|
||
If you completed the challenge, congratulations! Continue on to the knowledge
|
||
check in the next unit.
|
||
|
||
> Important
|
||
> If you had trouble completing this challenge, consider reviewing the previous
|
||
units before you continue on. All new ideas we discuss in other modules will
|
||
depend on your understanding of the ideas that were presented in this module.
|
||
|
||
- [Program.cs](./fortune/Program.cs)
|
||
|
||
---
|
||
|
||
## Summary
|
||
|
||
Your goal was to learn how to create your own methods to perform specific task
|
||
s. You learned to move reusable code into methods to minimize repeating code.
|
||
You also learned to use pseudo-code and placeholder methods to tackle a complex
|
||
problem. By creating small methods with specific responsibilities, you learned
|
||
to quickly build solutions for problems using efficient, readable code.
|