ms_learn_csharp/027_create_methods/027_csharp.md

1188 lines
35 KiB
Markdown
Raw Normal View History

2024-08-08 00:20:43 -04:00
# 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
```
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.
---
## 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.
### 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."
};
TellFortune();
void TellFortune() {
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.
---
## 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.