Methods


As explained, instance variables and methods are two of the primary constituents of classes. So far, the Building class contains data, but no methods. Although data-only classes are perfectly valid, most classes will have methods. Methods are subroutines that manipulate the data defined by the class and, in many cases, provide access to that data. Typically, other parts of your program will interact with a class through its methods.

A method contains one or more statements. In well-written C# code, each method performs only one task. Each method has a name, and it is this name that is used to call the method. In general, you can give a method whatever name you please. However, remember that Main( ) is reserved for the method that begins execution of your program. Also, don’t use C#’s keywords for method names.

When denoting methods in text, this book has used and will continue to use a convention that has become common when writing about C#. A method will have parentheses after its name. For example, if a method’s name is getval, then it will be written getval( ) when its name is used in a sentence. This notation will help you distinguish variable names from method names in this book.

The general form of a method is shown here:

 access ret-type name(parameter-list) {    // body of method }

Here, access is an access modifier that governs which other parts of your program can call the method. As explained earlier, the access modifier is optional. If not present, then the method is private to the class in which it is declared. For now, we will declare all methods as public so that they can be called by any other code in the program. The ret-type specifies the type of data returned by the method. This can be any valid type, including class types that you create. If the method does not return a value, its return type must be void. The name of the method is specified by name. This can be any legal identifier other than those already used by other items within the current scope. The parameter-list is a sequence of type and identifier pairs separated by commas. Parameters are variables that receive the value of the arguments passed to the method when it is called. If the method has no parameters, then the parameter list will be empty.

Adding a Method to the Building Class

As just explained, the methods of a class typically manipulate and provide access to the data of the class. With this in mind, recall that Main( ) in the preceding examples computed the area-per-person by dividing the total area by the number of occupants. While technically correct, this is not the best way to handle this computation. The calculation of area-per-person is something that is best handled by the Building class, itself. The reason for this conclusion is easy to understand: The area-per-person of a building is dependent upon the values in the area and occupants fields, which are encapsulated by Building. Thus, it is possible for the Building class to perform this calculation on its own. Furthermore, by adding this calculation to Building, you prevent each program that uses Building from having to perform this calculation manually. This prevents the unnecessary duplication of code. Finally, by adding a method to Building that computes the area-per-person, you are enhancing its object-oriented structure by encapsulating the quantities that relate directly to a building inside Building.

To add a method to Building, specify it within Building’s declaration. For example, the following version of Building contains a method called areaPerPerson( ) that displays the area-per-person for a building:

 // Add a method to Building. using System; class Building {   public int floors;    // number of floors   public int area;      // total square footage of building   public int occupants; // number of occupants   // Display the area per person.   public void areaPerPerson() {     Console.WriteLine("  " + area / occupants +                       " area per person");   } } // Use the areaPerPerson() method. class BuildingDemo {   public static void Main() {     Building house = new Building();     Building office = new Building();     // assign values to fields in house     house.occupants = 4;     house.area = 2500;     house.floors = 2;     // assign values to fields in office     office.occupants = 25;     office.area = 4200;     office.floors = 3;     Console.WriteLine("house has:\n  " +                       house.floors + " floors\n  " +                       house.occupants + " occupants\n  " +                       house.area + " total area");     house.areaPerPerson();     Console.WriteLine();     Console.WriteLine("office has:\n  " +                       office.floors + " floors\n  " +                       office.occupants + " occupants\n  " +                       office.area + " total area");     office.areaPerPerson();   } }

This program generates the following output, which is the same as before:

 house has:   2 floors   4 occupants   2500 total area   625 area per person office has:   3 floors   25 occupants   4200 total area   168 area per person

Let’s look at the key elements of this program, beginning with the areaPerPerson( ) method, itself. The first line of areaPerPerson( ) is

 public void areaPerPerson() {

This line declares a method called areaPerPerson that has no parameters. It is specified as public, so it can be used by all other parts of the program. Its return type is void. Thus, areaPerPerson( ) does not return a value to the caller. The line ends with the opening curly brace of the method body.

The body of areaPerPerson( ) consists solely of this statement:

 Console.WriteLine("  " + area / occupants +                   " area per person");

This statement displays the area-per-person of a building by dividing area by occupants. Since each object of type Building has its own copy of area and occupants, when areaPerPerson( ) is called, the computation uses the calling object’s copies of those variables.

The areaPerPerson( ) method ends when its closing curly brace is encountered. This causes program control to transfer back to the caller.

Next, look closely at this line of code from inside Main( ):

 house.areaPerPerson();

This statement invokes the areaPerPerson( ) method on house. That is, it calls areaPerPerson( ) relative to the house object, using the object’s name followed by the dot operator. When a method is called, program control is transferred to the method. When the method terminates, control is transferred back to the caller, and execution resumes with the line of code following the call.

In this case, the call to house.areaPerPerson( ) displays the area-per-person of the building defined by house. In similar fashion, the call to office.areaPerPerson( ) displays the area-per-person of the building defined by office. Each time areaPerPerson( ) is invoked, it displays the area-per-person for the specified object.

There is something very important to notice inside the areaPerPerson( ) method: The instance variables area and occupants are referred to directly, without preceding them with an object name or the dot operator. When a method uses an instance variable that is defined by its class, it does so directly, without explicit reference to an object and without use of the dot operator. This is easy to understand if you think about it. A method is always invoked relative to some object of its class. Once this invocation has occurred, the object is known. Thus, within a method, there is no need to specify the object a second time. This means that area and occupants inside areaPerPerson( ) implicitly refer to the copies of those variables found in the object that invokes areaPerPerson( ).

Returning from a Method

In general, there are two conditions that cause a method to return. The first, as the areaPerPerson( ) method in the preceding example shows, is when the method’s closing curly brace is encountered. The second is when a return statement is executed. There are two forms of return: one for use in void methods (those that do not return a value) and one for returning values. The first form is examined here. The next section explains how to return values.

In a void method, you can cause the immediate termination of a method by using this form of return:

 return ;

When this statement executes, program control returns to the caller, skipping any remaining code in the method. For example, consider this method:

 public void myMeth() {   int i;   for(i=0; i<10; i++) {     if(i == 5) return; // stop at 5     Console.WriteLine();   } }

Here, the for loop will only run from 0 to 5, because once i equals 5, the method returns.

It is permissible to have multiple return statements in a method, especially when there are two or more routes out of it. For example,

 public void myMeth() {   // ...   if(done) return;   // ...   if(error) return; }

Here, the method returns if it is done or if an error occurs. Be careful, however. Having too many exit points in a method can destructure your code, so avoid using them casually.

To review: A void method can return in one of two ways—its closing curly brace is reached, or a return statement is executed.

Returning a Value

Although methods with a return type of void are not rare, most methods will return a value. In fact, the ability to return a value is one of the most useful features of a method. You have already seen an example of a return value: when we used the Math.Sqrt( ) function to obtain a square root in Chapter 3.

Return values are used for a variety of purposes in programming. In some cases, such as with Math.Sqrt( ), the return value contains the outcome of some calculation. In other cases, the return value may simply indicate success or failure. In still others, it may contain a status code. Whatever the purpose, using method return values is an integral part of C# programming.

Methods return a value to the calling routine using this form of return:

 return value;

Here, value is the value returned.

You can use a return value to improve the implementation of areaPerPerson( ). Instead of displaying the area-per-person, a better approach is to have areaPerPerson( ) return this value. Among the advantages to this approach is that you can use the value for other calculations. The following example modifies areaPerPerson( ) to return the area-per-person rather than displaying it:

 // Return a value from areaPerPerson(). using System; class Building {   public int floors;    // number of floors   public int area;      // total square footage of building   public int occupants; // number of occupants   // Return the area per person.   public int areaPerPerson() {     return area / occupants;   } } // Use the return value from areaPerPerson(). class BuildingDemo {   public static void Main() {     Building house = new Building();     Building office = new Building();     int areaPP; // area per person     // assign values to fields in house     house.occupants = 4;     house.area = 2500;     house.floors = 2;     // assign values to fields in office     office.occupants = 25;     office.area = 4200;     office.floors = 3;     // obtain area per person for house     areaPP = house.areaPerPerson();     Console.WriteLine("house has:\n  " +                       house.floors + " floors\n  " +                       house.occupants + " occupants\n  " +                       house.area + " total area\n  " +                       areaPP + " area per person");     Console.WriteLine();          // obtain area per person for office     areaPP = office.areaPerPerson();          Console.WriteLine("office has:\n  " +                       office.floors + " floors\n  " +                       office.occupants + " occupants\n  " +                       office.area + " total area\n  " +                       areaPP + " area per person");   } }

The output is the same as shown earlier.

In the program, notice that when areaPerPerson( ) is called, it is put on the right side of an assignment statement. On the left is a variable that will receive the value returned by areaPerPerson( ). Thus, after

 areaPP = house.areaPerPerson();

executes, the area-per-person of the house object is stored in areaPP.

Notice that areaPerPerson( ) now has a return type of int. This means that it will return an integer value to the caller. The return type of a method is important because the type of data returned by a method must be compatible with the return type specified by the method. Thus, if you want a method to return data of type double, then its return type must be type double.

Although the preceding program is correct, it is not written as efficiently as it could be. Specifically, there is no need for the areaPP variable. A call to areaPerPerson( ) can be used in the WriteLine( ) statement directly, as shown here:

 Console.WriteLine("house has:\n  " +                   house.floors + " floors\n  " +                   house.occupants + " occupants\n  " +                   house.area + " total area\n  " +                   house.areaPerPerson() + " area per person");

In this case, when WriteLine( ) is executed, house.areaPerPerson( ) is called automatically, and its value will be passed to WriteLine( ). Furthermore, you can use a call to areaPerPerson( ) whenever the area-per-person of a Building object is needed. For example, this statement compares the per-person areas of two buildings:

 if(b1.areaPerPerson() > b2.areaPerPerson())   Console.WriteLine("b1 has more space for each person");

Using Parameters

It is possible to pass one or more values to a method when the method is called. As explained, a value passed to a method is called an argument. Inside the method, the variable that receives the argument is called a parameter. Parameters are declared inside the parentheses that follow the method’s name. The parameter declaration syntax is the same as that used for variables. A parameter is within the scope of its method, and aside from its special task of receiving an argument, it acts like any other local variable.

Here is a simple example that uses a parameter. Inside the ChkNum class, the method isPrime( ) returns true if the value that it is passed is prime. It returns false otherwise. Therefore, isPrime( ) has a return type of bool.

 // A simple example that uses a parameter. using System; class ChkNum {   // Return true if x is prime.   public bool isPrime(int x) {     for(int i=2; i <= x/i; i++)       if((x %i) == 0) return false;     return true;   } } class ParmDemo {   public static void Main() {     ChkNum ob = new ChkNum();     for(int i=1; i < 10; i++)       if(ob.isPrime(i)) Console.WriteLine(i + " is prime.");       else Console.WriteLine(i + " is not prime.");   } }

Here is the output produced by the program:

 1 is prime. 2 is prime. 3 is prime. 4 is not prime. 5 is prime. 6 is not prime. 7 is prime. 8 is not prime. 9 is not prime.

In the program, isPrime( ) is called nine times, and each time a different value is passed. Let’s look at this process closely. First, notice how isPrime( ) is called. The argument is specified between the parentheses. When isPrime( ) is called the first time, it is passed value 1. Thus, when isPrime( ) begins executing, the parameter x receives the value 1. In the second call, 2 is the argument, and x then has the value 2. In the third call, the argument is 3, which is the value that x receives, and so on. The point is that the value passed as an argument when isPrime( ) is called is the value received by its parameter, x.

A method can have more than one parameter. Simply declare each parameter, separating one from the next with a comma. For example, here the ChkNum class is expanded by adding a method called leastComFactor( ), which returns the smallest factor that its two arguments have in common. In other words, it returns the smallest whole number value that can evenly divide both arguments.

 // Add a method that takes two arguments. using System; class ChkNum {   // Return true if x is prime.   public bool isPrime(int x) {     for(int i=2; i <= x/i; i++)       if((x %i) == 0) return false;     return true;   }   // Return the least common factor.   public int leastComFactor(int a, int b) {     int max;     if(isPrime(a) | isPrime(b)) return 1;     max = a < b ? a : b;     for(int i=2; i <= max/2; i++)       if(((a%i) == 0) & ((b%i) == 0)) return i;     return 1;   } } class ParmDemo {   public static void Main() {     ChkNum ob = new ChkNum();     int a, b;     for(int i=1; i < 10; i++)       if(ob.isPrime(i)) Console.WriteLine(i + " is prime.");       else Console.WriteLine(i + " is not prime.");     a = 7;     b = 8;     Console.WriteLine("Least common factor for " +                       a + " and " + b + " is " +                       ob.leastComFactor(a, b));                            a = 100;     b = 8;     Console.WriteLine("Least common factor for " +                       a + " and " + b + " is " +                       ob.leastComFactor(a, b));     a = 100;     b = 75;     Console.WriteLine("Least common factor for " +                       a + " and " + b + " is " +                       ob.leastComFactor(a, b));                          } }

Notice that when leastComFactor( ) is called, the arguments are also separated by commas. The output from the program is shown here:

 1 is prime. 2 is prime. 3 is prime. 4 is not prime. 5 is prime. 6 is not prime. 7 is prime. 8 is not prime. 9 is not prime. Least common factor for 7 and 8 is 1 Least common factor for 100 and 8 is 2 Least common factor for 100 and 75 is 5

When using multiple parameters, each parameter specifies its own type, which can differ from the others. For example, this is perfectly valid:

 int myMeth(int a, double b, float c) {  // ...

Adding a Parameterized Method to Building

You can use a parameterized method to add a new feature to the Building class: the ability to compute the maximum number of occupants for a building assuming that each occupant must have a certain minimal space. This new method is called maxOccupant( ). It is shown here:

 /* Return the maximum number of occupants if each    is to have at least the specified minimum area. */ public int maxOccupant(int minArea) {   return area / minArea; }

When maxOccupant( ) is called, the parameter minArea receives the minimum space needed for each occupant. The method divides the total area of the building by this value and returns the result.

The entire Building class that includes maxOccupant( ) is shown here:

 /*    Add a parameterized method that computes the    maximum number of people that can occupy a    building assuming each needs a specified    minimum space. */ using System; class Building {   public int floors;    // number of floors   public int area;      // total square footage of building   public int occupants; // number of occupants   // Return the area per person.   public int areaPerPerson() {     return area / occupants;   }   /* Return the maximum number of occupants if each      is to have at least the specified minimum area. */   public int maxOccupant(int minArea) {     return area / minArea;   } } // Use maxOccupant(). class BuildingDemo {   public static void Main() {     Building house = new Building();     Building office = new Building();     // assign values to fields in house     house.occupants = 4;     house.area = 2500;     house.floors = 2;     // assign values to fields in office     office.occupants = 25;     office.area = 4200;     office.floors = 3;     Console.WriteLine("Maximum occupants for house if each has " +                       300 + " square feet: " +                       house.maxOccupant(300));     Console.WriteLine("Maximum occupants for office if each has " +                       300 + " square feet: " +                       office.maxOccupant(300));   } }

The output from the program is shown here:

 Maximum occupants for house if each has 300 square feet: 8 Maximum occupants for office if each has 300 square feet: 14

Avoiding Unreachable Code

When creating methods, you should avoid causing a situation in which a portion of code cannot, under any circumstances, be executed. This is called unreachable code, and it is considered incorrect in C#. The compiler will issue a warning message if you create a method that contains unreachable code. For example:

 public void m() {   char a, b;   // ...   if(a==b) {     Console.WriteLine("equal");     return;   } else {     Console.WriteLine("not equal");     return;   }   Console.WriteLine("this is unreachable"); }

Here, the method m( ) will always return before the final WriteLine( ) statement is executed. If you try to compile this method, you will receive a warning. In general, unreachable code constitutes a mistake on your part, so it is a good idea to take unreachable code warnings seriously.




C# 2.0(c) The Complete Reference
C# 2.0: The Complete Reference (Complete Reference Series)
ISBN: 0072262095
EAN: 2147483647
Year: 2006
Pages: 300

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net