4. Using Methods in the C# Class Library

4.1. Understanding Method Interfaces

A method consists of two parts: an interface and a body. The interface specifies the method name, along with information about the data that the method requires and produces when it is called. The body contains the list of statements the computer executes when the method is called. As an example, when you write the Main method for a program, first you write the interface:

static void Main()

Then you write the body:

{
  // method statements go here
}

To this point, we've ignored the interface and focused on the body. Now, we're going to focus on interfaces, since you need to understand how to interpret a method's interface in order to use the method properly in your program. The C# Class Library documentation contains detailed information on each method in the library, including its interface and information about how to use it.

Most methods are like miniature programs: they take input, perform some processing, and produce some output. Unlike the programs you write, however, methods rarely get their input from the keyboard, and rarely display their output on the screen. Instead, they get their input from variables in the Main method, and return their output to variables in the Main method, to be used in further processing. Let's look at this process in detail.

4.2. The Math.Pow Method

Suppose you are writing a program in which you need to raise a value to a given power. Perhaps your program computes the area of a circle using the formula

There is no built-in C# operator that can raise a variable to a given power. In this particular case, you could use multiplication instead of exponentiation:

double area = 3.1415 * radius * radius;

But what if you needed to raise a value to the 8th power? Repeated multiplication would clutter the code, or in the case of fractional powers, might not do the job at all.

If your program needs to raise a number to a large or fractional power, you might turn to the C# Library to find a method that could help you do the job. In the Math class, you would find a method named Pow which does just that. To use Math.Pow in your program, you must write a method call statement that supplies it with the correct number and type of input data values (called parameters), and obtains its result (called the return value). The necessary information appears in the class library documentation for Math.Pow, reproduced below:

This documentation contains the following important pieces of information about the Math.Pow method:

  • A description of what the method does ("Returns a specified number raised to the specified power.").

  • The interface of the method (located in the shaded section labeled Syntax).

  • A description of the method's parameters (inputs to the method).

  • A description of the method's return value (the value produced by the method).

It might help to think about Math.Pow as a special little machine that takes two inputs: the base (x) and the exponent (y), performs the work of doing the exponentiation, and returns the result, as indicated in the following diagram:

To use this method in your program, you write a method call statement that 1) names the method you wish to call, 2) provides the input values the method needs to do its job, and 3) stores the method's result in a variable for later use. Here is an example of a method call statement that calls the Math.Pow method to raise the value 3.5 to the power 2:

double r = 3.5;
double rsquared = Math.Pow(r, 2.0); // raises r to the 2nd power

In this code fragment, the variable r provides the input value for Pow's x parameter, and the literal value 2.0 provides the input value for Pow's y parameter. The value returned by the method is stored in the variable rsquared.

Like the highlighted statement above, most method call statements have the following form:

return-type variable-name = class-name.method-name(parameter-list);

where

  • return-type is the method's return type.

  • class-name is the class in which the method you are calling is contained.

  • method-name is the name of the method.

  • parameter-list is a list of expressions separated by commas which provide input values for the method's parameters.

The method interface specifies the method's name, return type, and required parameters in compact form. Here is the interface for Math.Pow:

public static double Pow(double x, double y)

To interpret the interface, you begin by finding the method name, located to the left of the opening parenthesis:

public static double Pow(double x, double y)

Working to the left, you find the method's return type. The return type indicates what sort of value the method produces as its result when you call it:

public static double Pow(double x, double y)

Pow produces a double value (as you might expect), so when we use it, we usually store the result in a double variable. Methods that produce values should be called in an expression -- usually in an assignment statement, like the one shown above. The value produced by the method is the value of the method call expression.

Continuing to the left, the word static indicates that when you call this method, you must prefix the method name with the name of the method's class, followed by a dot:

public static double Pow(double x, double y)

So, in the method call statement, you write Math.Pow(...) to indicate that you wish to call the method named Pow in the class named Math.

Now, look inside the parenthesis of the interface to see the parameters:

static double Pow(double x, double y)

This method requires us to provide two double values in the method call. When we write the two expressions in the call, we separate them with a comma, like this:

double rsquared = Math.Pow(r, 2.0);

Notice that the parameter input values supplied in the method call statement do not use the same names as the parameters listed in the method interface for Pow. In fact, the parameter names listed in the method interface have nothing to do with the names of the variables in the code calling the Pow method. Instead, it is the order of parameters that counts. The first parameter in the call statement, r, provides the value for the first parameter in the method interface; the second parameter in the call statement, 2.0, provides the value for the second parameter in the interface; and so on.

One point of confusion you have to watch out for involves terminology. The term parameter can be used to refer either to a parameter definition in a method interface (ex. double y), or to a parameter input value in a method call statement (ex. 2.0). We use the term formal parameter to denote the former, and actual parameter to denote the latter. In our example, r and 2.0 are actual parameters; x and y are formal parameters. As mentioned above, the names of the formal and actual parameters don't need to match, but the the data types of the actual parameters used in the method call statement must be compatible with the data types specified by the formal parameters. Formal parameter names that appear in a method interface are there only to help the programmer read the method documentation.

You may be wondering about the requirement that the parameters be of type double. What if you wanted to cube an int? You can use Pow to to do computations on integers as well as doubles. Here's how you would do it:

Console.Write("Enter a number, and I'll cube it for you:");
int num = Convert.ToInt32(Console.ReadLine());
int result = (int) Math.Pow(num, 3);    // Use a cast to convert the result to an int

When you attempt to call Math.Pow() with int parameters. C# automatically widens them to double values, in the same way that it automatically widens an int-type expression when you assign it to a double variable. All you have to remember to do is to use a cast to convert the double result to an int, so it can be stored in an int variable.

For now, try to fix two basic ideas in your mind:

  • A method interface is your road map that tells you how you write a method call statement to use the method.

  • A method interface is something you refer to when you write the statement to use a method, not a statement you would put in your program to use the method.

4.3. The Convert.ToInt32 Method

Remember the ToInt32 method I introduced earlier in this chapter? Here's an example of how you might use it:

string s = Console.ReadLine();  
if (s != "") {
  int i = Convert.ToInt32(s);
  ... do something with i ...
}

In this example, ToInt32 gets the characters to convert to an integer from the variable s. It performs the conversion and returns the numeric result, which is stored in the variable i for further use. In the highlighted method call statement that invokes ToInt32, s is the parameter that supplies input to the Int32 method.

Here's the interface for the ToInt32 method as it appears in the library:

public static int ToInt32(string s)

Start by locating the method name to the left of the open parenthesis:

public static int ToInt32(string s)

To the left of the method name is the return type:

public static int ToInt32(string s)

This return type indicates that the ToInt32 method produces an int value.

We're almost done! Now, we look inside the parenthesis to find the method's parameter list. The parameter list specifies the information that you must provide for the method to use when you call the method:

public static int ToInt32(string s)

This method has just one parameter: a string parameter named s. When you call this print method, you must provide a string-type expression in parenthesis. Here are several examples of how you might do this:

i = Convert.ToInt32("56");             // "56" is a string literal
i = Convert.ToInt32("-" + strDigits);  // "-" + strDigits is a string expression
i = Convert.ToInt32(str);              // str is a string variable

4.4. Void Methods

For our last example, let's take the familiar Write() method in the Console class:

static void Write(long value)

Again, we begin by locating the name:

static void Write(long value)

Now, look to the left of the name to find the return type:

static void Write(long value)

This requires some explanation. There is no data type named void. The void return type is used for methods that do not produce a value. Such methods must be called in a statement by themselves, and may not be used in an expression. This should make sense to you; you've never used the Write() method in an assignment statement.

On to the parameter list:

static void Write(long value)

This method requires a single long-type value. It will also accept int, short, and byte expressions, automatically widening them to a long. But what about double and string values? How can a method that accepts only integer data be used with other data types? Answer: it can't! The Console class actually defines more than one method named Write(). Here is a partial list:

static void Write(bool value)

static void Write(char value)

static void Write(double value)

static void Write(long value)

static void Write(string value)

static void Write(Object value)

All of these methods have the same name and return type, and require exactly one parameter. Each method, however, accepts a different kind of value. (The last one handles all kinds of objects.) When you call the print method with an int expression, a different method is executed than when you call the Write() method with a double expression, because each data type requires special handling. The compiler examines the expression you write in parenthesis, determines its type, and automatically selects the correct method to invoke.

The Write() method is not the only method that has several versions to handle different kinds of data. Several methods in the Math class work that way, too. I encourage you to take a look at the Math class documentation to see for yourself.