4.2. Declaring Methods

Let's talk in a bit more detail about how we specify an object's behaviors. Recall from Chapter 3 that an object's methods may be thought of as operations that the object can perform. In order for an object A to request some operation of an object B, A needs to know the specific language with which to communicate with B. That is:

  • Object A needs to be clear as to exactly which of B's methods/operations A wants B to perform. Think of yourself as object A and a pet dog as object B. Do you want your dog to sit? Stay? Heel? Fetch?

  • Depending on the method request, object A may need to give B some additional information so that B knows exactly how to proceed. If you tell your dog to fetch, the dog needs to know what to fetch: A ball? A stick? The neighbor's cat?

  • Object A also needs to know how or whether B will report back the outcome of what it has been asked to do. In the case of a command to fetch something, your dog will hopefully bring the requested item to you as an outcome. However, if your dog is in another room and you call out the command "sit," you won't see the result of your command; you have to trust that the dog has done what you have asked it to do.

We take care of communicating these three aspects of each method by defining a method header. We must then program the behind-the-scenes logic for how B will perform the requested operation, also known as the method body. In the case of our dog fetch example, the method header might be the following:

bool Fetch(string item)

Let's look a little more closely at method headers.

4.2.1. Method Headers

A method header is a formal specification (from a programming standpoint) of how that method is to be invoked. A method header includes the following:

  • The method's name

  • An optional list of comma-separated formal parameters (specifying their names and types) to be passed to the method enclosed in parentheses

  • A method's return type—that is, the data type of the information that will be passed back by object B to object A, if any, when the method is finished executing

As an example, here is a typical method header that we might define for the Student class:

bool    RegisterForCourse (string courseID, int secNo)
return type  method name   comma-separated list of formal parameters,
                           enclosed in parentheses
                           (parentheses may be left empty)

NOTE

When casually referring to a method such as RegisterForCourse in narrative text, many authors attach an empty set of parentheses, (), to the method name; for example, RegisterForCourse(). This doesn't necessarily imply that the formal header has no arguments, however.

4.2.2. Passing Arguments to Methods

The purpose of passing arguments into a method is twofold:

  • To provide the object receiving the request with some (optional) additional information necessary to do its job

  • To (optionally) guide its behavior in some fashion

In the RegisterForCourse method shown previously, for example, it's necessary to tell the method which course we want it to register for by passing in the course ID (for example, MATH 101) and the section number (for example, 10, which happens to meet Monday nights from 8–10 p.m.

Had we instead declared the RegisterForCourse method header with an empty parameter list, the method (presumably) would already have all the information it needed to register a course:

bool RegisterForCourse()

In fact, it is quite common for methods to produce results solely based on the information stored internally within an object, in which case no additional guidance is needed in the form of arguments. For example, the following method is designed to be parameterless (that is, it takes no arguments) because a Student object can presumably tell us its age (based on its birthDate field, perhaps) without having to be given any qualifying information:

int GetAge()

Let's say, however, that we wanted a Student object to be able to report its age expressed either in years (rounded to the nearest year) or in months; in such a case, we might want to declare the GetAge method as follows:

int GetAge(string ageType)

We would pass in an string argument to serve as a control flag for informing the Student object of how we want the answer to be returned; that is, we might program the GetAge method to ensure the following:

  • If we pass in a value of IN_YEARS, it means that we want the answer to be returned in terms of years (for example, 30).

  • If we pass in a value of IN_MONTHS, we want the answer to be returned in terms of months (for example, 30 × 12 = 360).

Using string parameters instead of, say, an integer parameter can make the code listing easier to read and understand.

NOTE

An alternative way of handling the requirement to retrieve the age of a Student object in two different formats would be to define two separate methods, such as the following:

int GetAgeInYears()
  int GetAgeInMonths()

4.2.3. Method Return Types

The RegisterForCourse method as previously declared is shown to have a return type of bool, which implies that this method will return one of the following two values:

  • A value of true to signal "mission accomplished"—namely, that the Student object has successfully registered for the course that it was instructed to register for

  • A value of false, to signal that the mission has failed for some reason; perhaps the desired section was full, or the student didn't meet the prerequisites of the course, or the requested course/section was cancelled, and so on

NOTE

In Part Three of the book, you'll learn techniques for communicating and determining precisely why the mission has failed when we discuss exception handling.

Note that a method need not return anything—that is, it may go about its business silently, without reporting the outcome of its efforts. If so, it is declared to have a return type of void (another C# keyword).

Here are several additional examples of method headers that we might define for the Student class:

  • void SetName(string newName)

    This method requires one argument—a string representing the new name that we want this Student to assume—and performs "silently" by setting the internal name field of the Student to whatever value is being passed into the method, returning no answer (a return type of void) in response.

  • void SwitchMajor(string newDepartment, Professor newAdvisor)

    This method represents a request for a Student to change the major field of study, which involves designating both a new academic department (for example, BIOLOGY) as well as a reference to the Professor object that is to serve as the student's advisor in this new department.

The preceding example demonstrates that we can declare parameters to be of any type, including user-defined types; the same is true for the return type of a method:

  • Professor GetAdvisor()

    This method is used to ask a Student object who the advisor is. Rather than merely returning the name of the advisor, the Student object returns a reference to the Professor object as a whole (as recorded in Student field facultyAdvisor).

    You'll see a need for returning references to objects in this fashion shortly, when we explore how objects interact.

Note that a method can return only one result or answer, which may seem limiting. What if, for example, we want to ask a Student object for a list of all the courses that the student has ever taken? Must we ask for them one by one through multiple method calls? Fortunately not; the result handed back by a method can actually be a reference to an object of arbitrary complexity, including a special type of object called a collection that can contain multiple other objects. We'll talk about collections in more depth in Chapter 6.

4.2.4. Method Bodies

When we design and program a class in an OO language, we must not only provide headers for all of its methods but also program the internal details of how each method should behave when it is invoked. These internal programming details, known as the method body, are enclosed within braces, {...}, immediately following the method header, as follows:

public class Student
{
  // Fields.
  double gpa;
  // other fields omitted from this snippet...

  // Here is a full-blown method, complete with a block of code to be
						// executed when the method is invoked.
						bool IsHonorsStudent() {
						// The programming details of what this method is to do
						// go between the braces...this is the method body.
						// "gpa" is a field of the Student class, declared above.
						if (gpa >= 3.5) {
						return true;   // true means "yes, this is an honors student"
						}
						else {

return false;  // false means "no, this isn't an honors student"
						}
						} // end of the method body

// etc.
}

4.2.5. Methods Implement Business Rules

The logic contained within a method body defines the business logic, also known as business rules, for an abstraction. In the preceding IsHonorsStudent method, for example, there is a single business rule for determining whether or not a student is an honors student:

"If a student has a grade point average (GPA) of 3.5 or higher, then he/she is an honors student."

This rule is implemented in the preceding method through the use of a simple if test. Suppose that the business rules underlying this method were more complex—say, the rules were as follows:

"In order for a student to be considered an honors student, the student must:

  1. Have a grade point average (GPA) of 3.5 or higher;

  2. Have taken at least three courses;

  3. Have received no grade lower than 'B' in any of these courses."

Our method logic would then of necessity be more complex:

bool IsHonorsStudent() {
    // Pseudocode. 
						if ((gpa >= 3.5) && 
						( number of courses taken 
						>= 3) && 
						( no grades lower than a B have been received )) { 
      return true;
    }
    else {
      return false;
    }
  }

4.2.6. The return Statement

A return statement is a jump statement that is used to exit a method and to send whatever information is returned by the method:

public int GetAge() {

    return age;
}

In the preceding example, the GetAge method has a return type of int, and the age field is placed after the return keyword to indicate that the value of the age field will be returned when the method exits. Whenever a return statement is executed, the method containing that return statement stops executing, and execution control returns to the code that invoked the method in the first place.

For methods with a return type of void, the return keyword can be used by itself, as a complete statement:

return;

However, it turns out that for methods with a return type of void, the use of a return statement is optional. If omitted, a return; statement is implied as the last line of the method. That is, the following two versions of method DoSomething are equivalent:

public void DoSomething() {
  int x = 3;
  int y = 4;
  int z = x + y;
}

And:

public void DoSomething() {
  int x = 3;
  int y = 4;
  int z = x + y;
  return;
}

The bodies of methods with a non-void return type must include at least one explicit return statement. The return keyword in such a case must be followed by an expression that evaluates to the proper type to match the method's return type:

return expression;

For example, if a method is defined to have a return type of int, any of the following return statements would be acceptable:

return 13;     // returning a constant integer value

return x;      // assuming x is declared to be an int

return x + y;  // assuming both x and y are declared to be ints

And so forth.

A method body is permitted to include more than one return statement if desired. For an example of a method containing multiple return statements, let's look once again at the IsHonorsStudent method discussed previously:

bool IsHonorsStudent() {
  if (gpa >= 3.5) {
    return true;   // first return statement

}
  else {
    return false;  // second return statement
  }
}

Good programming practice, however, is to have only one return statement in a method and to use a locally declared variable to capture the result that is to ultimately be returned. Having only a single return statement can make it easier to follow the execution flow of a complicated method. Although it is not a particularly complicated method, here is an alternative version of the IsHonorsStudent method that observes this practice:

bool IsHonorsStudent() {
  // Declare a local variable to keep track of the outcome;
						// arbitrarily initialize it to false.
						bool honors = false;

  if (gpa >= 3.5) {
    honors = true;
  }
  else {
    honors = false;
  }

  // We now have a single return statement at the end of our method.
						return honors;
}

4.2.7. Naming Suggestions

Inventing descriptive names for both methods and parameters help to make methods self-documenting. For example, the following method header:

void SwitchMajor(string newDepartment, Professor newAdvisor)

is much more self-explanatory than this alternative version:

void Switch(string d, Professor p)

In the latter case, we don't know what is being "switched," or what values for d and p would be relevant, without referring to the documentation for this method. Yet, to the compiler, both versions of the header are equally acceptable.

NOTE

Of course, one could argue that we'd always want to look at the documentation of a method anyway to determine its intended purpose and proper usage; but making the header self-documenting is even better.

C# method names are crafted using a style known as Pascal casing, wherein the first letter of the name is in uppercase; the first letter of each subsequent concatenated word in the variable name is in uppercase; and the rest of the characters are in lowercase. As an example, SwitchMajor is an appropriate method name, whereas neither Switchmajor (lowercase m) nor switchMajor (lowercase s) would be appropriate.

NOTE

Recall from Chapter 1 that most variable names use what is known as Camel casing, which is the same as Pascal casing except that the first letter is lowercase with Camel casing, whereas the first letter is capitalized with Pascal casing.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset