-
Techniques of Passing Arguments
|
|
Passing an Argument by Value
|
|
When calling a methods that takes one or more arguments, we
made sure we provided the necessary value. This is because an argument is always
required and the calling method must provide a valid value when calling such a
method.
Passing an Argument by Reference
|
|
Consider the following program:
using System;
public class Payroll
{
static void Earnings(double ThisWeek, double Salary)
{
ThisWeek = 42.50;
Console.WriteLine("\nIn the Earnings() function,");
Console.Write("Weekly Hours = ");
Console.WriteLine(ThisWeek);
Console.Write("Salary = ");
Console.WriteLine(Salary);
Console.Write("Weekly Salary: = ");
Console.WriteLine(ThisWeek * Salary);
}
static int Main()
{
double Hours, Rate;
Rate = 15.58;
Hours = 26.00;
Console.WriteLine("In the Main() method,");
Console.Write("\nWeekly Hours = ");
Console.Write(Hours);
Console.Write("\nSalary = ");
Console.WriteLine(Rate);
Console.Write("Weekly Salary = ");
Console.WriteLine(Hours * Rate);
Console.WriteLine("\nCalling the Earnings() method");
Earnings(Hours, Rate);
Console.Write("\nAfter calling the Earnings() method, ");
Console.WriteLine("\nin the Main() function,");
Console.Write("\nWeekly Hours = ");
Console.Write(Hours);
Console.Write("\nSalary = ");
Console.WriteLine(Rate);
Console.Write("Weekly Salary = ");
Console.WriteLine(Hours * Rate);
Console.Write("\n");
return 0;
}
}
This would produce:
In the Main() method,
Weekly Hours = 26
Salary = 15.58
Weekly Salary = 405.08
Calling the Earnings() method
In the Earnings() function,
Weekly Hours = 42.5
Salary = 15.58
Weekly Salary: = 662.15
After calling the Earnings() method,
in the Main() function,
Weekly Hours = 26
Salary = 15.58
Weekly Salary = 405.08
Press any key to continue
Notice that the weekly hours and salary values are the same
before and after calling the Earnings() method.
When you declare a variable in a program, the compiler
reserves an amount of space for that variable. If you need to use that variable
somewhere in your program, you call it and make use of its value. There are two
major issues related to a variable: its value and its location in the memory.
The location of a variable in memory is referred to as its address.
If you supply the argument using its name, the compiler only
makes a copy of the argument’s value and gives it to the calling method.
Although the calling method receives the argument’s value and can use it in any
way, it cannot (permanently) alter it. C# allows a calling method to modify the
value of a passed argument if you find it necessary. If you want the calling
method to modify the value of a supplied argument and return the modified value,
you should pass the argument using its reference.
To pass an argument as a reference, when defining and when
calling the method, precede the argument's data type with the ref
keyword. You can pass 0, one, or more arguments as reference in the program or
pass all arguments as reference. The decision as to which argument(s) should be
passed by value or by reference is based on whether or not you want the called
method to modify the argument and permanently change its value.
Another option consists of passing an
argument using the out keyword. Here is an example:
using System;
class Exercise
{
static void Initializer(out double n)
{
n = 128.44;
}
public static int Main()
{
double Number = 15.25;
Console.WriteLine("Number = {0}", Number);
return 0;
}
}
If you pass an argument with out, any modification
made on the argument would be kept when the method ends. When calling a method
that takes an out argument, precede the argument with the out
keyword. Here is an example:
using System;
class Exercise
{
static void Initializer(out double n)
{
n = 128.44;
}
public static int Main()
{
double Number = 15.25;
Console.WriteLine("Number = {0}", Number);
Initializer(out Number);
Console.WriteLine("Number = {0}", Number);
return 0;
}
}
This would produce:
Number = 15.25
Number = 128.44
Practical Learning: Passing Arguments By Reference
|
|
- To pass arguments by reference, change the Cylinder.cs file as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Geometry1
{
class Cylinder
{
public void GetRadius(ref double rad)
{
Console.Write("Radius: ");
rad = double.Parse(Console.ReadLine());
}
public void GetHeight(out double h)
{
Console.Write("Height: ");
h = double.Parse(Console.ReadLine());
}
public double CalculateBaseArea(double rad)
{
return rad * rad * Math.PI;
}
public double CalculateLateralArea(double rad, double hgt)
{
return 2 * Math.PI * rad * hgt;
}
public double CalculateTotalArea(double rad, double hgt)
{
return 2 * Math.PI * rad * (hgt + rad);
}
public double CalculateVolume(double rad, double hgt)
{
return Math.PI * rad * rad * hgt;
}
public void Process()
{
double Radius = 0.00;
double Height = 0.00;
double BaseArea;
double LateralArea;
double TotalArea;
double Volume;
Console.WriteLine("Enter the dimensions of the cylinder");
GetRadius(ref Radius);
GetHeight(out Height);
BaseArea = CalculateBaseArea(Radius);
LateralArea = CalculateLateralArea(Radius, Height);
TotalArea = CalculateTotalArea(Radius, Height);
Volume = CalculateVolume(Radius, Height);
Console.WriteLine("\nCylinder Characteristics");
Console.WriteLine("Radius: {0}", Radius);
Console.WriteLine("Height: {0}", Height);
Console.WriteLine("Base: {0:F}", BaseArea);
Console.WriteLine("Lateral: {0:F}", LateralArea);
Console.WriteLine("Total: {0:F}", TotalArea);
Console.WriteLine("Volume: {0:F}", Volume);
}
}
}
|
- Execute the application to test it. Here is an example:
Enter the dimensions of the cylinder
Radius: 24.55
Height: 20.85
Cylinder Characteristics
Radius: 24.55
Height: 20.85
Base: 1893.45
Lateral: 3216.16
Total: 7003.05
Volume: 39478.34
|
- Close the DOS window
A typical program involves a great deal of names that
represent variables and methods of various kinds. The compiler does not allow
two variables to have the same name in the same method. Although two methods
should have unique names in the same program, a class can have different methods
with the same name if you follow some rules. The ability to have various methods
with the same name in the same program is referred to as method overloading. To
perform overloading, the methods must have different numbers or different
type(s) of arguments.
The moment of inertia is the ability of a beam to resist
bending. It is calculated with regard to the cross section of the beam. Because
it depends on the type of section of the beam, its calculation also depends on
the type of section of the beam. In this exercise, we will review different
formulas used to calculate the moment of inertia. Since this exercise is for
demonstration purposes, you do not need to be a Science Engineering major to
understand it.
Practical Learning: Overloading a Method
|
|
- Create a new Console Application named MomentOfInertia1
- Change the file as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class Exercise
{
// Rectangle
static double MomentOfInertia(double b, double h)
{
return b * h * h * h / 3;
}
static int Main()
{
double Base, Height;
Console.WriteLine("Enter the dimensions of the Rectangle");
Console.Write("Base: ");
Base = double.Parse(Console.ReadLine());
Console.Write("Height: ");
Height = double.Parse(Console.ReadLine());
Console.WriteLine("\nMoment of inertia with " +
"regard to the X axis: ");
Console.WriteLine("I = {0}mm",
MomentOfInertia(Base, Height));
Console.WriteLine();
return 0;
}
}
|
- Execute the application. Here is an example of running the program:
Enter the dimensions of the Rectangle
Base: 2.44
Height: 3.58
Moment of inertia with regard to the X axis:
I = 37.3179390933333mm
|
- Close the DOS window
- A circle, and thus a semi-circle, requires only a radius. Since the
other version of the MomentOfInertia() function requires two arguments, we
can overload it by providing only one argument, the radius.
To overload the above MomentOfInertia() method, type the following in the
file:
|
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class Exercise
{
// Rectangle
static double MomentOfInertia(double b, double h)
{
return b * h * h * h / 3;
}
// Semi-Circle
static double MomentOfInertia(double R)
{
const double PI = 3.14159;
return R * R * R * R * PI/ 8;
}
static int Main()
{
double Base, Height;
double Radius;
Console.WriteLine("Enter the dimensions of the Rectangle");
Console.Write("Base: ");
Base = double.Parse(Console.ReadLine());
Console.Write("Height: ");
Height = double.Parse(Console.ReadLine());
Console.WriteLine("\nMoment of inertia with regard to the X axis: ");
Console.WriteLine("I = {0}mm", MomentOfInertia(Base, Height));
Console.Write("\nEnter the radius: ");
Radius = double.Parse(Console.ReadLine());
Console.WriteLine("Moment of inertia of a semi-circle " +
"with regard to the X axis: ");
Console.WriteLine("I = {0}mm", MomentOfInertia(Radius));
Console.WriteLine();
return 0;
}
}
|
- Execute the program. Here is an example:
Enter the dimensions of the Rectangle
Base: 4.25
Height: 2.55
Moment of inertia with regard to the X axis:
I = 23.49028125mm
Enter the radius: 5.35
Moment of inertia of a semi-circle with regard to the X axis:
I = 321.717471644992mm
|
- Close the DOS window
-
Here are the formulas considered for a triangle:
As you can see, the rectangle and the triangle are using the same
dimension types. This means that we can provide only the same kinds of
arguments, the base and the height, to calculate the moment of inertia. This
also means that the compiler will not allow us to write two methods that
have the same name, the same number of arguments, and the same types of
arguments because that would violate the rule of function overloading.
In order to overload the MomentOfInertia() function, we will add an
argument that will never be used; this argument will serve only as a
“witness” to set the difference between both versions of the function. This
“witness” argument can be anything: an integer, a character, a string, a
float, etc. For our example, we will make it a simple integer. To use the
version applied to the triangle, we will provide this argument to overload
the MomentOfInertia() function. When called with only two arguments, the
rectangle version will apply.
Change the file as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class Exercise
{
// Rectangle
static double MomentOfInertia(double b, double h)
{
return b * h * h * h / 3;
}
// Semi-Circle
static double MomentOfInertia(double R)
{
const double PI = 3.14159;
return R * R * R * R * PI/ 8;
}
// Triangle
static double MomentOfInertia(double b, double h, int i)
{
return b * h * h * h / 12;
}
static int Main()
{
double Base = 7.74, Height = 14.38, Radius = 12.42;
Console.WriteLine(
"Rectangle - Moment of inertia with regard to the X axis: ");
Console.WriteLine("I = {0}mm", MomentOfInertia(Base, Height));
Console.WriteLine("\nSemi-Circle - Moment of inertia of a " +
"semi-circle with regard to the X axis: ");
Console.WriteLine("I = {0}mm", MomentOfInertia(Radius));
Console.WriteLine("\nEnter the dimensions of the triangle");
Console.Write("Base: ");
Base = double.Parse(Console.ReadLine());
Console.Write("Height: ");
Height = double.Parse(Console.ReadLine());
Console.WriteLine(
"\nTriangle - Moment of inertia with regard to the X axis: ");
Console.WriteLine("I = {0}mm", MomentOfInertia(Base, Height, 1));
Console.WriteLine();
return 0;
}
}
|
- Execute the program. Here is an example:
Rectangle - Moment of inertia with regard to the X axis:
I = 7671.78395376mm
Semi-Circle - Moment of inertia of a semi-circle with regard to the X axis:
I = 9344.28126291881mm
Enter the dimensions of the triangle
Base: 5.52
Height: 3.84
Triangle - Moment of inertia with regard to the X axis:
I = 26.04662784mm
|
- Close the DOS window
Class Construction and Destruction
|
|
Imagine you are writing a program for a business that sells
flowers:
Flower |
|
|
|
|
|
Type |
Daisies |
Lilies |
Roses |
Live Plants |
Orchids |
Color |
White |
Mixed |
Red |
Green |
Pink |
Arrangement |
Vase |
Vase |
Bouquet |
Basket |
Vase |
Price |
37.15 |
29.95 |
85.95 |
60.95 |
55.95 |
Consider the following program:
using System;
public class Flower
{
public int Type;
public int Color;
public char Arrangement;
public double UnitPrice;
}
public class Exercise
{
static int Main()
{
var flr = new Flower();
Console.WriteLine("Flower Type: {0}", flr.Type);
Console.WriteLine("Flower Color: {0}", flr.Color);
Console.WriteLine("Arrangement: {0}", flr.Arrangement);
Console.WriteLine("Price: {0:C}", flr.UnitPrice);
Console.WriteLine("");
return 0;
}
}
This would produce:
Flower Type: 0
Flower Color: 0
Arrangement:
Price: $0.00
Press any key to continue . . .
If you declare a variable of a class in your program, when
the program comes up, the compiler reserves enough memory space for each member
of the class. The memory space reserved for each member variable is filled with
an initial value based on its type. For a string object, the space would
be left empty. For an integer type, the space would be filled with 0. A better
way to take care of this type is to provide a value whose role would be to
initialize the member variables with the values of your choice. A method that
initializes an object can return any value but it is preferable to be of type
void because its primary purpose is to reset the values. Since this method
would give a starting value to all member variables that need to be initialized,
it should have an equivalent argument for each of the member variables that it
would initialize. Here is an example:
public class Flower
{
public int Type;
public int Color;
public char Arrangement;
public double UnitPrice;
public void Initializer(int tp, int clr, char arng, double price)
{
}
}
The method initializer does not have to initialize all
members of the class. For example, the previous execution of the program shows
that the member variables that are of type string are initialized with
empty strings. In such a case, you may not have to initialize such variables. To
implement a method initializer, simply assign its argument to the corresponding
member variable of the class. Here are examples:
public class Flower
{
public int Type;
public int Color;
public char Arrangement;
public double UnitPrice;
public void Initializer(int tp, int clr, char arng, double price)
{
Type = tp;
Color = clr;
Arrangement = arng;
UnitPrice = price;
}
}
You can call a method initializer after declaring the
instance of the class to give it initial values. Here is an example:
using System;
public class Flower
{
public int Type;
public int Color;
public char Arrangement;
public double UnitPrice;
public void Initializer(int tp, int clr, char arng, double price)
{
Type = tp;
Color = clr;
Arrangement = arng;
UnitPrice = price;
}
}
public class Exercise
{
static int Main()
{
var flr = new Flower();
flr.Initializer(3, 7, 'V', 37.15D);
Console.WriteLine("Flower Type: {0}", flr.Type);
Console.WriteLine("Flower Color: {0}", flr.Color);
Console.WriteLine("Arrangement: {0}", flr.Arrangement);
Console.WriteLine("Price: {0:C}", flr.UnitPrice);
Console.WriteLine("");
return 0;
}
}
|
|
This would produce:
Flower Type: 3
Flower Color: 7
Arrangement: V
Price: $37.15
Press any key to continue . . .
Using a method initializer, after initializing the object,
you can use the values it holds as you see fit.
A constructor is a special method that is created when the
object comes to life. This particular method holds the same name as the class
and it initializes the object whenever that object is created. When you create a
class, if you don't declare a constructor, the compiler creates one for you;
this is useful because it lets all other objects of the program know that the
object exists. This compiler-created constructor is called the default
constructor. If you want, you can create your own constructor.
To create a constructor, declare a method that holds the
same name as the class. Remember that the method must not return any value.
Here is an example:
namespace FlowerShop
{
public class Flower
{
Flower()
{
}
}
}
When you declare an instance of the class, whether you use
that object or not, a constructor for the object is created. When an instance of
a class has been declared, the default constructor is called, whether the object
is used or not. This is illustrated in the following program:
using System;
namespace FlowerShop
{
public class Flower
{
public int Type;
public int Color;
public char Arrangement;
public decimal UnitPrice;
public Flower()
{
Console.WriteLine("New Flower Order");
}
}
public class Exercise
{
static int Main()
{
var flr = new Flower();
return 0;
}
}
}
This would produce:
New Flower Order
Press any key to continue...
As you can see, even though the flr variable was not used,
just its declaration was enough to signal it. You might find it sometimes
convenient to create your own constructor because, whether you create an empty
constructor or not, this does not negatively impact your program.
The Constructor Initializer
|
|
A constructor can be used to initialize the member variables
of a class. As such, a constructor provides a valuable alternative to a method
initializer, the type of method we saw earlier. To use a constructor to
initialize the member variables of a class, provide as arguments the necessary
variables that you intend to initialize. You don't have to initialize all member
variables in the constructor, only those that need to be initialized. In fact,
you should initialize only those members that you think the other objects would
need when using this object. This means that your object may have fields that,
either the external objects don't need to modify (or access) or the member
variable(s) will be initialized later when called from the needed object(s).
To implement a default constructor, you can just initialize
the desired members of the class. For a member variable of a numeric type, you
can just assign the desired constant to each. If the variable is a character,
assign a single-quoted symbol to it. If the variable is a string, then assign a
double-quoted value to the variable. Here are examples:
using System;
namespace FlowerShop
{
public class Flower
{
public int Type;
public int Color;
public char Arrangement;
public decimal UnitPrice;
public Flower()
{
Type = 1;
Color = 1;
Arrangement = 'V';
UnitPrice = 0M;
}
}
public class Program
{
static int Main()
{
var flr = new Flower();
Console.WriteLine("Flower Type: {0}",
flr.Type);
Console.WriteLine("Flower Color: {0}",
flr.Color);
Console.WriteLine("Arrangement: {0}",
flr.Arrangement);
Console.WriteLine("Price: {0:C}",
flr.UnitPrice);
Console.WriteLine("");
return 0;
}
}
}
|
|
The default constructor is the favorite place to provide
default values to the members of a class. Besides the default constructor, you
can add as many constructors as you judge necessary. This feature of C# allows
you to create various constructors for different reasons. This also means that
the methods or constructors of a class can be overloaded.
One of the rules of method overloading consists of having
methods with different types of arguments. The most basic constructor you would
create can use a single argument. When implementing a constructor that takes one
argument, you should initialize the member that corresponds to the unique
argument and initialize the other members with default values. Here is an
example:
using System;
namespace FlowerShop
{
public class Flower
{
public int Type;
public int Color;
public char Arrangement;
public decimal UnitPrice;
public Flower()
{
Type = 1;
Color = 1;
Arrangement = 'V';
UnitPrice = 0M;
}
public Flower(int tp)
{
Type = tp;
Color = 1;
Arrangement = 'V';
UnitPrice = 0M;
}
}
}
If you create a class with only one constructor as in the
current example, when declaring an instance of the class, you must use that
constructor: you cannot use the default constructor that doesn't take an
argument. When declaring the variable, initialize it with a constructor with
parentheses and provide the value(s) in the parentheses of the constructor. Here
is an example:
using System;
namespace FlowerShop
{
public class Flower
{
public string Type;
public string Color;
public string Arrangement;
public double UnitPrice;
public Flower()
{
Type = "";
Color = "Red";
Arrangement = "Basket";
UnitPrice = 35.95D;
}
public Flower(string tp)
{
Type = tp;
Color = "Red";
Arrangement = "Basket";
UnitPrice = 35.95D;
}
}
public class Exercise
{
static int Main()
{
var flr = new Flower("Tulips");
Console.WriteLine("Flower Type: {0}", flr.Type);
Console.WriteLine("Flower Color: {0}", flr.Color);
Console.WriteLine("Arrangement: {0}", flr.Arrangement);
Console.WriteLine("Price: {0:C}", flr.UnitPrice);
Console.WriteLine("");
return 0;
}
}
}
This would produce:
Flower Type: Tulips
Flower Color: Red
Arrangement: Basket
Price: $35.95
Press any key to continue . . .
In the same way, you can create different constructors for
different initializations, although it would not be realistic to create a
different constructor for each variable. If you create different constructors
with different arguments to initialize (remember the rules of method
overloading), when declaring the classes, make sure you initialize each instance
with the right number of arguments; otherwise, the compiler would complain.
If you create a class with only one constructor and that
constructor has at least one argument, the default constructor would not be
available anymore. If you want to access a default constructor of an object, you
have two alternatives:
- If you don't create any constructor at all on a class, the default
constructor would always be available whenever you invoke that class
- If you create at least one constructor on a class and supply at least
one argument to that constructor, you must explicitly create a default
constructor for your class.
The Destructor of a Class
|
|
As opposed to a constructor, a destructor is called when a
program has finished using an object. A destructor does the cleaning behind the
scenes. Like the default constructor, the compiler always creates a default
destructor if you don't create one. Unlike the constructor, the destructor
cannot be overloaded. This means that, if you decide to create a destructor, you
can have only one. Like the default constructor, a destructor also has the same
name as its class. This time, the name of the destructor starts with a tilde
"~".
To create a destructor, type ~ followed by the name of the
class. Here is an example:
namespace FlowerShop
{
public class Flower
{
public string Type;
public string Color;
public string Arrangement;
public decimal UnitPrice;
public Flower()
{
Type = "";
Color = "Red";
Arrangement = "Basket";
UnitPrice = 35.95M;
}
public Flower(string tp)
{
Type = tp;
Color = "Red";
Arrangement = "Basket";
UnitPrice = 35.95M;
}
~Flower()
{
}
}
}
|
|