560 lines
17 KiB
Markdown
560 lines
17 KiB
Markdown
|
# Create C# methods with parameters
|
||
|
|
||
|
Learn how to use different types of input parameters in methods
|
||
|
|
||
|
### Learning objectives
|
||
|
|
||
|
- Learn more about using parameters
|
||
|
|
||
|
- Understand method scope
|
||
|
|
||
|
- Understand pass-by-reference and pass-by-value parameter types
|
||
|
|
||
|
- Learn how to use optional and named arguments
|
||
|
|
||
|
## Introduction
|
||
|
|
||
|
Methods have the ability to perform operations on input. Passing parameters to
|
||
|
your methods allows you to perform the method's task with different input
|
||
|
values. Using method parameters lets you extend your code while keeping your
|
||
|
program organized and readable. If you consider a method to be a black box that
|
||
|
accepts input and performs a single task, you can quickly divide a large
|
||
|
problem into workable pieces.
|
||
|
|
||
|
Suppose you need to write code that performs the same operation on different
|
||
|
sets of input. You might have three different arrays, and need to display the
|
||
|
contents of each one. You can create a `DisplayArray` method that accepts a
|
||
|
single array as input and displays the contents. Instead of writing code to
|
||
|
display each individual array, you can call the same method and provide the
|
||
|
different arrays as input.
|
||
|
|
||
|
Parameters can make your methods more robust while still performing the same
|
||
|
general task. In this module, you'll learn more about working with parameters
|
||
|
and solidify your understanding of methods.
|
||
|
|
||
|
### Learning Objectives
|
||
|
|
||
|
In this module, you will:
|
||
|
|
||
|
- Learn more about using parameters
|
||
|
- Understand method scope
|
||
|
- Understand pass-by-reference and pass-by-value parameter types
|
||
|
- Learn how to use optional and named arguments
|
||
|
|
||
|
#### Prerequisites
|
||
|
|
||
|
- Experience using C# data types including `int`, `string`, arrays, and 2D
|
||
|
arrays
|
||
|
- Experience using switch statements, if-else statements, and for-loops
|
||
|
- Experience using the `Random` class to generate a random number.
|
||
|
- Basic understanding of C# methods
|
||
|
|
||
|
---
|
||
|
|
||
|
## Exercise
|
||
|
|
||
|
### Use parameters in methods
|
||
|
|
||
|
When creating methods, you'll often want to provide some information for the
|
||
|
method to use. Information consumed by a method is called a parameter. You can
|
||
|
supply as many parameters as needed to accomplish its task, or none at all.
|
||
|
|
||
|
The terms 'parameter' and 'argument' are often used interchangeably. However,
|
||
|
'parameter' refers to the variable in the method signature. The 'argument' is
|
||
|
the value passed when the method is called.
|
||
|
|
||
|
### Add parameters to methods
|
||
|
|
||
|
Parameters in a method work similar to variables. A parameter is defined by
|
||
|
specifying the data type followed by the name of the parameter. Parameters are
|
||
|
declared in the method signature, and the values for the parameters are
|
||
|
provided by the method caller instead of being initialized inside the method
|
||
|
itself. Consider the following code:
|
||
|
|
||
|
```cs
|
||
|
CountTo(5);
|
||
|
|
||
|
void CountTo(int max) {
|
||
|
for (int i = 0; i < max; i++) {
|
||
|
Console.Write($"{i}, ");
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
In this example, the method `CountTo` accepts an integer parameter named `max`.
|
||
|
The parameter is referenced in the `for` loop of the method. When `CountTo` is
|
||
|
called, the integer 5 is supplied as an argument.
|
||
|
|
||
|
In this exercise, you'll learn how to create and use your own method parameters.
|
||
|
|
||
|
#### Create a method with parameters
|
||
|
|
||
|
In this task, you'll create a method that adjusts scheduled times to a different
|
||
|
GMT time zone. The method should accept a list of times, the current time zone,
|
||
|
and the new time zone. Let's get started!
|
||
|
|
||
|
Enter the following code into the code editor:
|
||
|
|
||
|
```cs
|
||
|
int[] schedule = {800, 1200, 1600, 2000};
|
||
|
```
|
||
|
|
||
|
To create a method with parameters, enter the following code on a new blank
|
||
|
line:
|
||
|
|
||
|
```cs
|
||
|
void DisplayAdjustedTimes(int[] times, int currentGMT, int newGMT) {
|
||
|
|
||
|
}
|
||
|
```
|
||
|
|
||
|
Notice that parameters are declared similar to the way you declare variables,
|
||
|
using the data type followed by the variable name. You can use parameters of
|
||
|
any data type, such as `string`, `bool`, `int`, `arrays`, and more! Multiple
|
||
|
parameters in a method are always comma separated.
|
||
|
|
||
|
Enter the following code in the `DisplayAdjustedTimes` method:
|
||
|
|
||
|
```cs
|
||
|
int diff = 0;
|
||
|
if (Math.Abs(newGMT) > 12 || Math.Abs(currentGMT) > 12) {
|
||
|
Console.WriteLine("Invalid GMT");
|
||
|
}
|
||
|
```
|
||
|
|
||
|
Notice how you don't have to declare the variables `newGMT` and `currentGMT`
|
||
|
since they're already declared in the method signature. You also don't
|
||
|
initialize the variables since the method assumes the caller supplies those
|
||
|
arguments with assigned values.
|
||
|
|
||
|
In this step, you create `int diff` to store the time difference and then check
|
||
|
to see that the provided GMT values are between -12 and 12. Using `Math.Abs`
|
||
|
gives you the absolute value of a number, so the GMT values are invalid if
|
||
|
they're greater than 12.
|
||
|
|
||
|
To calculate the time difference, update the `DisplayAdjustedTimes` method as
|
||
|
follows:
|
||
|
|
||
|
```cs
|
||
|
int diff = 0;
|
||
|
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));
|
||
|
} else {
|
||
|
diff = 100 * (Math.Abs(newGMT) + Math.Abs(currentGMT));
|
||
|
}
|
||
|
```
|
||
|
|
||
|
In this code, you check to see whether you need to add or subtract the absolute
|
||
|
values of the GMT time zones to get the difference in hours. If the GMT values
|
||
|
share the same sign (both positive or both negative), then the hours difference
|
||
|
is equal to the difference between the two numbers. If the GMT values have
|
||
|
opposite signs, then the difference is equal to the sum of the two numbers.
|
||
|
Since hours are represented in hundreds, you multiply the result by 100.
|
||
|
|
||
|
To display the results, enter the following code at the end of the
|
||
|
`DisplayAdjustedTimes` method:
|
||
|
|
||
|
```cs
|
||
|
for (int i = 0; i < times.Length; i++) {
|
||
|
int newTime = ((times[i] + diff)) % 2400;
|
||
|
Console.WriteLine($"{times[i]} -> {newTime}");
|
||
|
}
|
||
|
```
|
||
|
|
||
|
To call your method, enter the following code after the `int[]` schedule
|
||
|
variable declaration:
|
||
|
|
||
|
```cs
|
||
|
DisplayAdjustedTimes(schedule, 6, -6);
|
||
|
```
|
||
|
|
||
|
Notice that both variables and literals can be supplied as arguments to a
|
||
|
method. By using input parameters, the method isn't restricted to using the
|
||
|
values of global variables.
|
||
|
|
||
|
### Check Your Work
|
||
|
|
||
|
At the Terminal command prompt, enter `dotnet run`
|
||
|
|
||
|
Verify that your code produces the following output:
|
||
|
|
||
|
```txt
|
||
|
800 -> 2000
|
||
|
1200 -> 0
|
||
|
1600 -> 400
|
||
|
2000 -> 800
|
||
|
```
|
||
|
|
||
|
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](./parameters/Program.cs)
|
||
|
|
||
|
### Recap
|
||
|
|
||
|
Here's what you've learned about parameters so far:
|
||
|
|
||
|
- Information can be passed to methods in the form of parameters.
|
||
|
- Parameters are declared in the method signature.
|
||
|
- Multiple parameters are separated by commas.
|
||
|
- Methods can accept variable or literal arguments.
|
||
|
|
||
|
---
|
||
|
|
||
|
## Exercise
|
||
|
|
||
|
### Understand method scope
|
||
|
|
||
|
`for` loops, `if-else` statements, and methods all represent different types of
|
||
|
code blocks. Each code block has its own 'scope'. 'Scope' is the region of a
|
||
|
program where certain data is accessible. Variables declared inside a method,
|
||
|
or any code block, are only accessible within that region. As programs become
|
||
|
more complicated, this pattern helps programmers consistently use clearly named
|
||
|
variables and maintain easy to read code.
|
||
|
|
||
|
In this exercise, you'll learn more about method scope by working with
|
||
|
different types of methods and variables.
|
||
|
|
||
|
#### Test variable scope
|
||
|
|
||
|
Statements declared outside of any code block are called top-level statements.
|
||
|
Variables declared in top-level statements are called 'global variables'. Global
|
||
|
variables aren't restricted to any scope, and can be used anywhere throughout
|
||
|
the program. Global variables can be useful for different methods that need to
|
||
|
access the same data. However, it's important to pay attention to variable
|
||
|
names in different scopes.
|
||
|
|
||
|
Enter the following code into the code editor:
|
||
|
|
||
|
```cs
|
||
|
string[] students = {"Jenna", "Ayesha", "Carlos", "Viktor"};
|
||
|
|
||
|
DisplayStudents(students);
|
||
|
DisplayStudents(new string[] {"Robert","Vanya"});
|
||
|
|
||
|
void DisplayStudents(string[] students) {
|
||
|
foreach (string student in students) {
|
||
|
Console.Write($"{student}, ");
|
||
|
}
|
||
|
Console.WriteLine();
|
||
|
}
|
||
|
```
|
||
|
|
||
|
In this code, you create a global `students` array, and a method
|
||
|
`DisplayStudents` that accepts a parameter with the same name.
|
||
|
|
||
|
Save and run the code to observe the following output:
|
||
|
|
||
|
```txt
|
||
|
Jenna, Ayesha, Carlos, Viktor,
|
||
|
Robert, Vanya,
|
||
|
```
|
||
|
|
||
|
Notice that the method parameter `student` takes precedence over the global
|
||
|
`student` array. It's important to be deliberate about what global variables you
|
||
|
want your methods to use.
|
||
|
|
||
|
Delete the previous code.
|
||
|
|
||
|
Enter the following code into the Editor:
|
||
|
|
||
|
```cs
|
||
|
PrintCircleArea(12);
|
||
|
|
||
|
void PrintCircleArea(int radius) {
|
||
|
double pi = 3.14159;
|
||
|
double area = pi * (radius * radius);
|
||
|
Console.WriteLine($"Area = {area}");
|
||
|
}
|
||
|
```
|
||
|
|
||
|
This code calculates and displays the area of a circle.
|
||
|
|
||
|
Attempt to reference the variables inside of the `PrintCircleArea` method by
|
||
|
updating your code as follows:
|
||
|
|
||
|
```cs
|
||
|
PrintCircleArea(12);
|
||
|
double circumference = 2 * pi * radius;
|
||
|
```
|
||
|
|
||
|
Error messages appear informing you that the names `pi` and `radius` don't exist
|
||
|
in the current scope. Those variables only exist within the `PrintCircleArea`
|
||
|
method scope.
|
||
|
|
||
|
Delete the incorrect code and add the following code:
|
||
|
|
||
|
```cs
|
||
|
void PrintCircleCircumference(int radius) {
|
||
|
double pi = 3.14159;
|
||
|
double circumference = 2 * pi * radius;
|
||
|
Console.WriteLine($"Circumference = {circumference}");
|
||
|
}
|
||
|
```
|
||
|
|
||
|
Since the variable `pi` is set to the same fixed value and used in both methods,
|
||
|
this value is a good candidate for a global variable. In this example, `radius`
|
||
|
isn't a global variable so that you can call the methods with different values
|
||
|
of `radius` without updating a variable each time.
|
||
|
|
||
|
Update your code to the following:
|
||
|
|
||
|
```cs
|
||
|
double pi = 3.14159;
|
||
|
|
||
|
void PrintCircleArea(int radius) {
|
||
|
double area = pi * (radius * radius);
|
||
|
Console.WriteLine($"Area = {area}");
|
||
|
}
|
||
|
|
||
|
void PrintCircleCircumference(int radius) {
|
||
|
double circumference = 2 * pi * radius;
|
||
|
Console.WriteLine($"Circumference = {circumference}");
|
||
|
}
|
||
|
```
|
||
|
|
||
|
Now both methods can reference the same value of `pi` without needing to define
|
||
|
it. You might have already guessed that methods can call other methods.
|
||
|
Generally, as long as a method is defined within the scope of your program, it
|
||
|
can be called anywhere.
|
||
|
|
||
|
Add a new method to your code as follows:
|
||
|
|
||
|
```cs
|
||
|
double pi = 3.14159;
|
||
|
PrintCircleInfo(12);
|
||
|
PrintCircleInfo(24);
|
||
|
|
||
|
void PrintCircleInfo(int radius) {
|
||
|
Console.WriteLine($"Circle with radius {radius}");
|
||
|
PrintCircleArea(radius);
|
||
|
PrintCircleCircumference(radius);
|
||
|
}
|
||
|
```
|
||
|
|
||
|
In this code, you create a new method `PrintCircleInfo` to call the existing
|
||
|
methods. The value of `radius` is also passed down to each method. Creating
|
||
|
modularized methods can help keep your code organized and easy to read.
|
||
|
|
||
|
Save and run the code to observe the following output:
|
||
|
|
||
|
```txt
|
||
|
Circle with radius 12
|
||
|
Area = 452.38896
|
||
|
Circumference = 75.39815999999999
|
||
|
Circle with radius 24
|
||
|
Area = 1809.55584
|
||
|
Circumference = 150.79631999999998
|
||
|
```
|
||
|
|
||
|
- [Program.cs](./parameter_scope/Program.cs)
|
||
|
|
||
|
### Recap
|
||
|
|
||
|
Here's what you've learned about method scope so far:
|
||
|
|
||
|
Variables declared inside of a method are only accessible to that method.
|
||
|
Variables declared in top-level statements are accessible throughout the program.
|
||
|
Methods don't have access to variables defined within different methods.
|
||
|
Methods can call other methods.
|
||
|
|
||
|
---
|
||
|
|
||
|
## Exercise
|
||
|
|
||
|
### Use value and reference type parameters
|
||
|
|
||
|
In C#, variables can be categorized into two main types, value types and
|
||
|
reference types. These types describe how variables store their values.
|
||
|
|
||
|
Value types such as `int`, `bool`, `float`, `double`, and `char` directly
|
||
|
contain values. Reference types such as `string`, `array`, and objects (such as
|
||
|
instances of `Random`) don't store their values directly. Instead, reference
|
||
|
types store an address where their value is being stored.
|
||
|
|
||
|
### Parameters passed by value and passed by reference
|
||
|
|
||
|
When an argument is passed to a method, *value* type variables have their
|
||
|
values copied into the method. Each variable has its own copy of the value, so
|
||
|
the original variable isn't modified.
|
||
|
|
||
|
With reference types, the address of the value is passed into the method. The
|
||
|
variable given to the method references the value at that address, so
|
||
|
operations on that variable affect the value that is referenced by the other.
|
||
|
|
||
|
> Note
|
||
|
> It is important to remember that `string` is a reference type, but it is
|
||
|
immutable. That means once it has been assigned a value, it can't be altered.
|
||
|
In C#, when methods and operators are used to modify a string, the result that
|
||
|
is returned is actually a new string object.
|
||
|
|
||
|
In this exercise, you'll learn more about passing reference and value type
|
||
|
arguments into methods.
|
||
|
|
||
|
#### Test pass by value
|
||
|
|
||
|
Enter the following code into the code editor:
|
||
|
|
||
|
```cs
|
||
|
int a = 3;
|
||
|
int b = 4;
|
||
|
int c = 0;
|
||
|
|
||
|
Multiply(a, b, c);
|
||
|
Console.WriteLine($"global statement: {a} x {b} = {c}");
|
||
|
|
||
|
void Multiply(int a, int b, int c) {
|
||
|
c = a * b;
|
||
|
Console.WriteLine($"inside Multiply method: {a} x {b} = {c}");
|
||
|
}
|
||
|
```
|
||
|
|
||
|
The variables `a`, `b`, and `c` are passed to the `Multiply` method. The values
|
||
|
of the variables are printed during the method execution, and printed again
|
||
|
after the method is complete.
|
||
|
|
||
|
Integers are value types, which have their values copied when passed into
|
||
|
methods. What do you think the output of `c` will be?
|
||
|
|
||
|
Save and run your code to observe the following output:
|
||
|
|
||
|
```cs
|
||
|
inside Multiply method: 3 x 4 = 12
|
||
|
global statement: 3 x 4 = 0
|
||
|
```
|
||
|
|
||
|
Notice that the value of `c` is only altered within the `Multiply` method.
|
||
|
Outside of the method, `c` retains its original value.
|
||
|
|
||
|
#### Test pass by reference
|
||
|
|
||
|
Enter the following code into the code editor:
|
||
|
|
||
|
```cs
|
||
|
int[] array = {1, 2, 3, 4, 5};
|
||
|
|
||
|
PrintArray(array);
|
||
|
Clear(array);
|
||
|
PrintArray(array);
|
||
|
|
||
|
void PrintArray(int[] array) {
|
||
|
foreach (int a in array) {
|
||
|
Console.Write($"{a} ");
|
||
|
}
|
||
|
Console.WriteLine();
|
||
|
}
|
||
|
|
||
|
void Clear(int[] array) {
|
||
|
for (int i = 0; i < array.Length; i++) {
|
||
|
array[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
The code begins with `array` initialized to contain some integer values. The
|
||
|
values are displayed using the `PrintArray` method. The `Clear` method is called
|
||
|
on the array, and then the array is printed again.
|
||
|
|
||
|
Arrays are reference types. Reference types store the address of their values
|
||
|
in memory. What do you think the output will be?
|
||
|
|
||
|
Save and run your code to observe the following output:
|
||
|
|
||
|
```txt
|
||
|
1 2 3 4 5
|
||
|
0 0 0 0 0
|
||
|
```
|
||
|
|
||
|
Notice that the array remains altered outside of the `Clear` method scope. This
|
||
|
happens because the `Clear` method updated the values stored at each address.
|
||
|
|
||
|
#### Test with strings
|
||
|
|
||
|
Earlier, you learned that strings are an *immutable* type. Even though a string
|
||
|
is a reference type, unlike an array, its value can't be altered once it's
|
||
|
assigned. You might have noticed this if you've used methods such as
|
||
|
`string.Replace` or `string.ToUpper`. In this task, you'll learn to correct a
|
||
|
common error found when working with strings.
|
||
|
|
||
|
Enter the following code into the code editor:
|
||
|
|
||
|
```cs
|
||
|
string status = "Healthy";
|
||
|
|
||
|
Console.WriteLine($"Start: {status}");
|
||
|
SetHealth(status, false);
|
||
|
Console.WriteLine($"End: {status}");
|
||
|
|
||
|
void SetHealth(string status, bool isHealthy) {
|
||
|
status = (isHealthy ? "Healthy" : "Unhealthy");
|
||
|
Console.WriteLine($"Middle: {status}");
|
||
|
}
|
||
|
```
|
||
|
|
||
|
Save and run your code to observe the following output:
|
||
|
|
||
|
```txt
|
||
|
Start: Healthy
|
||
|
Middle: Unhealthy
|
||
|
End: Healthy
|
||
|
```
|
||
|
|
||
|
If the `SetHealth` method didn't output the status, you might have assumed the
|
||
|
method didn't execute correctly. Instead, a new string with the value
|
||
|
"Unhealthy" was created and then lost in the method scope.
|
||
|
|
||
|
To correct this problem, you can change `SetHealth` to use the global status
|
||
|
variable instead.
|
||
|
|
||
|
Update your code as follows:
|
||
|
|
||
|
```cs
|
||
|
string status = "Healthy";
|
||
|
|
||
|
Console.WriteLine($"Start: {status}");
|
||
|
SetHealth(false);
|
||
|
Console.WriteLine($"End: {status}");
|
||
|
|
||
|
void SetHealth(bool isHealthy) {
|
||
|
status = (isHealthy ? "Healthy" : "Unhealthy");
|
||
|
Console.WriteLine($"Middle: {status}");
|
||
|
}
|
||
|
```
|
||
|
|
||
|
In this code, you overwrite the global `status` variable with the new string
|
||
|
value.
|
||
|
|
||
|
Save and run your code to observe the following output:
|
||
|
|
||
|
```txt
|
||
|
Start: Healthy
|
||
|
Middle: Unhealthy
|
||
|
End: Unhealthy
|
||
|
```
|
||
|
|
||
|
Now the updated string is captured and stored correctly.
|
||
|
|
||
|
- [Program.cs](./value_and_ref_params/Program.cs)
|
||
|
|
||
|
### Recap
|
||
|
|
||
|
Here's what you've learned about value type and reference type parameters so
|
||
|
far:
|
||
|
|
||
|
- Variables can be categorized as value types and reference types.
|
||
|
- Value types directly contain values, and reference types store the address of
|
||
|
the value.
|
||
|
- Methods using value type arguments create their own copy of the values.
|
||
|
- Methods that perform changes on an array parameter affect the original input
|
||
|
array.
|
||
|
- String is an immutable reference type.
|
||
|
- Methods that perform changes on a string parameter don't affect the original
|
||
|
string.
|
||
|
|
||
|
---
|
||
|
|
||
|
##
|