Methods (functions inside of a class—all functions must be inside a class in C#) are an important tool in ASP.NET development because they enable you to determine at the time you write the code the order in which sections of code will run at runtime. Methods also enable you to better organize your code into discrete units based on the functionality provided by each one. For example, if you write code that multiplies two numbers and returns the result, that code is much more useful if it’s wrapped in a procedure. Using a method allows the code to be called from more than one place in your application as necessary, which enables you to reuse the code rather than rewrite it each time you need to multiply two numbers. Unlike Visual Basic, which has a Sub and a Function as distinct concepts, C# has only a single type of method, a function. Of course, you can create a method in C# without returning a value by declaring the function return type void. A special “type” in C#, void is used to specify that a method does not return a value as in this example:
// C# procedure that writes output to the browse private void WriteHello1(string FirstName Message.Text += "Hello, " + FirstName + "!<br/>" }
Note that in a C# function, the name of the procedure is followed by a set of empty parentheses. These parentheses have a purpose other than simply taking up space. You can place code between these parentheses to define one or more parameters that users must pass when they call the procedure. Parameters can be passed either by value (a copy of the value is passed to the procedure) or by reference (a reference to the location of the value is passed to the procedure, which allows the procedure to modify the original value). You use the keyword ref to specify that the parameter is to be passed by reference. If no keyword is used, the parameters will be passed by value. The following code shows some examples:
private void ModifyInt(int MyInt MyInt += 42 // Modified value will not be availabl // once this method returns private void ModifyInt(ref int MyInt MyInt += 42 // Modified value will be available t // calling method }
You can pass more than one parameter to a procedure simply by separating each parameter with a comma, as in the following example:
private void WriteHello(string Name1, string Name2 Response.Write("Hello to both " + Name1 + " and " + Name2 }
Note that you explicitly type the parameters by declaring the data type of each parameter as string. If any data type other than string is passed to the procedure, the method will not compile. Because the C# string type is just an alias for the System.String type, you could pass in a System.String instance as a parameter and there would be no type violation.
C# does not allow optional parameters, however, much of the same effect can be realized by using function overloading. Function overloading means that there is more than one method with the same name, but different parameters.
For instance, imagine that you have a method that accepts a person’s first name, like so:
private void WriteHello( string FirstName Message.Text += "Hello, " + FirstName + "!<br/>" }
Now let’s say that you embed this all over an application and then discover that you really need to make the last name available in some cases. One solution would be to create an additional method, as follows:
private void WriteHello(string FirstName, string LastName Message.Text += "Hello, " + FirstName + " " + LastName + "!<br/>" }
Now you can call WriteHello and pass in either a single string or two strings. In a more complex example, rather than having each overloaded method actually do some work, you would likely make all methods except one (the one that passes the largest number of parameters) into shell methods that simply call the version with the most parameters, adding default values when called. So you might re-create the WriteHello method that accepts a single string as follows:
private void WriteHello(string FirstName // Call the two-parameter method and default // to an empty string for last nam WriteHello(FirstName, "") }
This is not quite as convenient as optional parameters as implemented in Visual Basic .NET, but does allow the same functionality.
All the previous examples used the void return type, meaning that no value was returned from the method. There are two ways of getting values back from a method call. The first is by declaring a non-void return type. For instance, to safely divide two numbers we could do the following:
private int Divide(int Numerator, int Divisor if ( Divisor != 0 // the return keyword returns the value that follows i // to the calle return(Numerator/Divisor) els return(0) }
This method prevents me from dividing by 0, and returns 0 if division by 0 is requested. One thing to remember about returning values from a C# method is that there is no default return value. Every logical path in the method must return a value of the correct type. Thus, if I rewrite the method as follows, it will fail to compile:
private int Divide(int Numerator, int Divisor if ( Divisor!=0 return(Numerator/Divisor) els Response.Write("Error! Division by 0 requested!") }
The compile time error that C# will return for this method is “Not all code paths return a value.” If you say a method will return an int, it really must return one! This example returns an integer, but you can return any type, including complex types like classes and structures. The second way to return a value from a method is to use a ref parameter. When you say a parameter is passed by ref, rather than the actual value being passed to the method, a reference (very much like a pointer) is passed, so that changes to the parameter’s value will be visible back in the calling method. For instance:
private void RefTest(ref int Number Number += 5 private void CallRefTest( int foo = 5 RefTest(ref foo) // Now foo is 10 }
Note that when you pass a ref parameter you must precede the variable name with the keyword ref. When calling by reference, you must pass a variable, not a constant. Thus, the following will be invalid:
The compiler message related to this error is “An out or ref argument must be an lvalue.” An lvalue is an expression that can be placed on the left side of an equal sign used for assignment. Saying 5 = x (where we are using the single equal sign for assignment rather than the double equal sign used for testing equality) makes no sense, so 5 is not an lvalue.
In addition to ref, you can pass a parameter as an out parameter. This is similar to a ref, but unlike a ref, the parameter need not be initialized before being passed to the method. For example:
private void OutTest(out int Number Number = 5 private void CallOutTest( int foo // Now foo is not initialized // If I tried to use foo here, a compile time erro //will occur OutTest(out foo) // Now foo is 5 }
In this example, foo is declared but not initialized in CallOutTest. In OutTest, foo is assigned a value, and OutTest makes no assumptions about the value of Number being passed as a parameter. If rather than assigning a value to Number, I tried to use the value first, or even tried to increment the value using += rather than just assigning a value, a compile time error occurs.
Finally, you can change the accessibility of a method using the public, private, internal, and protected keywords. Methods are private by default, which means they can be called only from the module, class or struct they reside in. This is the exact opposite of the default in Visual Basic .NET, where methods are public by default.