3
New
Let's consider the following program.
a.cs
class zzz
{
static void Main()
{
yyy.abc();
}
}
class yyy
{
public void abc() {
System.Console.WriteLine("abc");
}
}
Compiler Error
a.cs(5,1) : error CS0120: An object reference is required
for the nonstatic field, method or property 'yyy.abc()'
This program contains one class called yyy which has a
function called abc. In Main() we are using the syntax yyy.abc() to call the
abc function as we did earlier. Within the abc function we have the code for
the function abc that will print the string "abc". On compiling this
program you will get an error as incomprehensible as ever!
But how is it that when we ran this program earlier we didn't
get an error? If you are still bewildered, wake up and smell the coffee! Didn't
you notice we removed the word 'static' while saying public void abc(). Hence
we get an error.
In our earlier programs when we wrote the function abc we
had written the word static which is missing now.
No, we are not going to tell you to add the word static and
execute the program. We are not that predictable! On the contrary, we shall do
something quite different and interesting. Keeping that in mind let's consider
the next program.
a.cs
class zzz
{
static void Main()
{
yyy a;
a.abc();
}
}
class yyy
{
public void abc()
{
System.Console.WriteLine("abc");
}
}
Compiler Error
a.cs(6,1): error CS0165: Use of unassigned local variable
'a'
Before we look into this program let's get our basics clear.
We have often used the statement 'int i' meaning that i was a variable that
looked like an int. When we used the statement 'string s', it meant that s was
a variable that looked like string. Similarly, in this program we are saying
yyy a. This implies that 'a' looks like yyy. What is yyy? It is the name of a
class. Here we do not call 'a' a variable, we call it an object. An object and
a variable can be used interchangeably.
Earlier, whenever we wanted to call a member from a class we
would say yyy.abc(); i.e. class name dot function name. But in our current
program we are saying a.abc(); We are using the same dot, but now it gives an
error saying - 'Use of unassigned local variable'. Note that the word member is
analogous with the word function.
But things still don't seem any clearer. So, let's go a step
further and add another statement a=new yyy(); Match your code with the one
below.
a.cs
class zzz
{
static void Main()
{
yyy a;
a=new yyy();
a.abc();
}
}
class yyy
{
public void abc()
{
System.Console.WriteLine("abc");
}
}
Output
abc
The word or keyword new must be followed by the name of a
class; You cannot substitute it with anything else, it must be a class. In our
case, we have given the statement as new yyy(). yyy is the name of an existing
class. But why have round brackets after the class name? The '(' and ')'
brackets are part of the syntax. And you very well know by now that you can't
argue with syntax.
Thus it is at this point i.e. after saying new, that the
object 'a' that looks like yyy is created.
We could have also called the object 'a' an instance of the class yyy.
Since the class yyy has only one function it will allocate memory for THAT one
function ONLY. Now we have an object 'a' that looks like class yyy. Once the
object is created, it can be used to access the function from class yyy. Hence,
now if we say a.abc() we will not get an error.
Thus an object is nothing but an instance or an occurrence
of a class. Therefore, 'a' is an instance of the class yyy. This is how you can
instantiate an object.
In order to create an object you must use the keyword 'new'.
Our next program will help you gain a better understanding of this concept.
a.cs
class zzz
{
static void Main()
{
int i;
i=new int();
}
}
At first we have int i, meaning i looks like int. Then we
have i=new int(); Executing this program will not generate any errors. But so
far whenever we used int i we never created the object i using new int(). This
is because C# does this internally for us. It saves us the trouble of doing so.
Then why doesn't C# do so for all the other objects that we create? This is
because C# recognizes only two types of classes.
The first type is one that the C# compiler knows of in
advance. int, long, bool, and string are classes that fall into this category.
These are predefined classes. But we call them data types because in C and C++
they were called data types and C# has a legacy of C and C++. So technically, when
we say int i it does i=new int(); internally.
The second type of classes that C# recognizes are the ones
that we create i.e. user-defined classes. For user-defined classes we have to
create objects ourselves. Thus anything other than the basic data-types must be
explicitly created.
So when we say 'yyy a' we are not creating the object at
this point. We are only declaring the object to be of type yyy. It is only when
we use the word 'new' that the object is created and memory is allocated for
the same. Therefore, when we have our own classes, that's the time we use new.
Without new you cannot create an object.
Static
You are certainly going to benefit by the patience you have
shown so far. To find out how, let's follow the next program.
a.cs
class zzz
{
static void Main()
{
yyy a;
a=new yyy();
a.abc();
yyy.pqr();
}
}
class yyy
{
public void abc()
{
System.Console.WriteLine("abc");
}
public static void pqr()
{
System.Console.WriteLine("pqr");
}
}
Output
abc
pqr
In this program we have two functions abc and pqr. It is of
significance to note that the function pqr has the word static whereas abc does
not. If you want to access the static function pqr you say yyy.pqr() and to
access the non static function abc you say a.abc(); You can't do the reverse
i.e. you cant say a.pqr() and yyy.abc().
a.cs
class zzz
{
static void Main()
{
yyy a;
a=new yyy();
yyy.abc();
a.pqr();
}
}
class yyy
{
public void abc()
{
System.Console.WriteLine("abc");
}
public static void pqr()
{
System.Console.WriteLine("pqr");
}
}
Compiler Error
a.cs(7,1): error CS0120: An object reference is required for
the nonstatic field, method, or property 'yyy.abc()'
a.cs(8,1): error CS0176: Static member 'yyy.pqr()' cannot be
accessed with an instance reference; qualify it with a type name instead
The word 'static' implies 'free'. Static signifies that you
can access a member or a function without creating an object. At last you are
enjoying the fruits of patience!
Observe that the function Main in zzz is static. This is
because we are not creating any object that looks like zzz. The crux is that if
you don't want to use 'new' and yet use the function then you must make the
function static.
In both cases a dot is used to reference the function. The
only difference is that a static member belongs to the class and as such we
don't need to create an object to access it. On the other hand, a non-static
member, that is the default, can be accessed only via an object of the class.
Thus WriteLine is a static function in Console as we did not create an object
that looks like Console to access it.
a.cs
class zzz
{
static void Main()
{
System.Console.WriteLine(yyy.i);
}
}
class yyy
{
public int i = 10;
}
Compiler Error
a.cs(5,26): error CS0120: An object reference is required
for the nonstatic field, method, or property 'yyy.i'
Why did we get an error? Think for thinking is the hardest
work there is, which is probably the reason why so few engage in it. If you
still haven't got it, let us enlighten you. The same rules for static apply to
functions as well as variables. Hence we get the above error.
a.cs
class zzz
{
static void Main()
{
yyy a = new yyy();
yyy b = new yyy();
a.j = 11;
System.Console.WriteLine(a.j);
System.Console.WriteLine(b.j);
yyy.i = 30;
System.Console.WriteLine(yyy.i);
}
}
class yyy
{
public static int i = 10;
public int j = 10;
}
Output
11
10
30
A static variable belongs to the class. Hence if we create a
static variable i, no matter how many objects we create that look like yyy,
there will be one and only one value of i as there is only one variable i
created in memory. Thus we access a static variable by prefacing with the name
of the class and not name of object. If the variable is non-static like j then
we have to use the syntax as explained earlier i.e. name of object dot name of
variable. Thus each time we create an object that looks like yyy we are
creating a new/another copy of the variable j in memory. We now have two j's in
memory one for a and another for b. Thus j is called an instance variable
unlike i. When we change the variable j of a to 11, the j of b remain at 10.
Thus functions are created in memory only once, irrespective
of the word static. If a class has no instance or non static variables then it
makes no sense to create multiple instances of the object as there will be no
way of distinguishing between the copies created.
Constructors
a.cs
class zzz
{
public static void Main()
{
yyy a;
System.Console.WriteLine("Main");
a=new yyy();
}
}
class yyy
{
public yyy()
{
System.Console.WriteLine("yyy");
}
}
Output
Main
yyy
In the above program we have a class called yyy. We also
have a function called yyy which happens to be having the same name as the name
of the class. We have a friend named Bunty. Coincidentally, the name of his pet
dog is also Bunty! Similarly, it is absolutely legal to have a function by the
same name as that of the class. In this case first we see Main and then we see
yyy displayed on the screen which means that the function yyy() gets called
automatically. Note, we have not called the function yyy explicitly.
This happens to be a special function and it is called a
'constructor'.
Initially we are saying yyy a. By doing so we are specifying
that 'a' looks like yyy. We are not creating an object that looks like yyy. The
next statement has System.Console.WriteLine, which will print 'Main'.
Thereafter, using new we are creating an object a. It is at this point that C#
calls the constructor i.e. it calls the function yyy(). Now you will see 'yyy'
displayed. This goes to prove that as soon as an object of a class is created,
C# automatically calls the constructor. A constructor gets called at the time
of birth or creation of the object. It has to have the same name as the name of
the class.
a.cs
class zzz
{
public static void Main()
{
yyy a;
System.Console.WriteLine("Main");
a=new yyy();
a.yyy();
}
}
class yyy
{
public yyy()
{
System.Console.WriteLine("yyy");
}
}
Compiler Error
a.cs(8,1): error CS0117: 'yyy' does not contain a definition
for 'yyy'
Here, we are calling the function yyy using the appropriate
syntax i.e. by saying a.yyy(). Now, run the compiler. Baffled by the
error? The error says 'yyy' does not contain
a definition for 'yyy'. The class yyy does contain a function called yyy which
got called in the previous example. Has C# developed amnesia all of a sudden?
What went wrong? Well, you cannot call this function using a.yyy() or yyy.yyy()
The catch is that when you have a function with the same name as that of the
class you cannot call it at all. It gets called automatically. C# does not give
anyone the authority to call such a function. It calls this function
automatically only at birth. Seems abnormal doesn't it!
But what is the purpose of having constructors?
A constructor can be used in cases where every time an
object gets created and you want some code to be automatically executed. The
code that you want executed must be put in the constructor. That code could be
anything, it could check for hard disk space, it could create a file or it
could connect to the net and bring a file over. What that code will do shall
vary from person to person.
To understand how and when the constructor gets called, let's
take into consideration our next example. Now remove the word 'public' in front
of yyy() as we have done below.
a.cs
class zzz
{
public static void Main()
{
yyy a;
System.Console.WriteLine("hi");
a=new yyy();
}
}
class yyy
{
yyy()
{
System.Console.WriteLine("yyy const");
}
}
Compiler Error
a.cs(7,3): error CS0122: 'yyy.yyy()' is inaccessible due to
its protection level.
Obviously, you will get an error. This is because without
the word public the function is private property. And when you trespass on
private property you have to face the consequences. In our case we are faced
with an error. By making the function public every one can use it, it is now
becomes public property! If the constructor is private then nobody can create
an object that looks like yyy.
Do you think constructors can return values? Let's try it
out and find out for ourselves.
a.cs
class zzz
{
public static void Main()
{
yyy a;
System.Console.WriteLine("hi");
a=new yyy();
}
}
class yyy
{
public int yyy()
{
System.Console.WriteLine("yyy const");
}
}
Compiler Error
a.cs(12,12): error CS0542: 'yyy': member names cannot be the
same as their enclosing type
Executing the above program generates an error. It says that
member i.e yyy cannot be the same as the enclosing type i.e class yyy. Now,
that is an error that you certainly didn't expect.
Let us analyze why we got this error.
Here we are saying public int yyy implying that the function
yyy() is returning an int. yyy() is a constructor and is called automatically
at the time an object is created. If a constructor is to return a value then to
whom should it return the value to? Since it is called automatically, there is
nothing that can accept the return value. Thus constructors cannot return
values. Also when a constructor gets called, an object is in the act of being
created. It has not yet been created. The keyword new first allocates memory
for the functions and the variables. After this it calls the constructor. When
the constructor finishes, then we say that the object has been created. Thus
the constructor has no one to return values to.
Now that we know constructors don't return values let's
return void instead.
a.cs
class zzz
{
public static void Main()
{
yyy a;
System.Console.WriteLine("hi");
a=new yyy();
}
}
class yyy
{
public void yyy()
{
System.Console.WriteLine("yyy const");
}
}
Compiler Error
a.cs(12,13): error CS0542: 'yyy': member names cannot be the
same as their enclosing type
Though we are returning void, we get the same error. This is
because C# is very sure of what it says. When you borrow from other people you
do so on the pretext that you will return it. It's a different story that you
never do! You rarely mean what you say. But when C# says that constructors
cannot return values it means 'constructors cannot return values', not even
'void'. Remember, there is nothing that can accept the return values. Hence
even void cannot be accepted. When a function returns a void we mean that it
will return no value at all. For a constructor, the word return makes no sense
at all.
Constructors with parameters
Just as we pass parameters to other functions, you can also
pass parameters to constructors.
a.cs
class zzz
{
public static void Main()
{
yyy a;
System.Console.WriteLine("hi");
a=new yyy("no");
}
}
class yyy
{
public yyy()
{
System.Console.WriteLine("yyy const");
}
}
Compiler Error
a.cs(7,3): error CS1501: No overload for method 'yyy' takes
'1' arguments
You are already aware of the fact that parameters are passed
to functions while calling them. Similarly, we will pass a parameter to the
constructor yyy while creating the object a; because it is at this point that
the constructor gets called.
Hence we are saying a=new yyy("no"). But on
compiling this program you get an error. Here, the constructor is being called
with a string 'no' as a parameter. But there is no variable in the constructor
yyy to store the value 'no'. Add 'string s' in the constructor yyy and watch
the error disappear.
a.cs
class zzz
{
public static void Main()
{
yyy a;
System.Console.WriteLine("hi");
a=new yyy("no");
}
}
class yyy
{
public yyy(string s)
{
System.Console.WriteLine(s);
}
}
Output
hi
no
At first WriteLine will display 'hi'. Then we have a
constructor yyy that takes a string 'no' as a parameter and accepts it in a
variable s. Thus the moment the constructor yyy is called 'no' will be
displayed. This is because the constructor yyy contains code that will print
the value stored in the variable s. This is how constructors with parameters
are called.
So far we created only one instance of the class yyy. In the
following program we are creating two instances of the class yyy, 'a' and
'b'.
a.cs
class zzz
{
public static void Main()
{
yyy a,b;
System.Console.WriteLine("hi");
a=new yyy("no");
b=new yyy();
}
}
class yyy
{
public yyy(string s)
{
System.Console.WriteLine(s);
}
}
Compiler Error
a.cs(8,3): error CS1501: No overload for method 'yyy' takes
'0' arguments
While creating the object 'a' the constructor yyy is being
passed a parameter 'hi'. In case of the object 'b' the constructor will be
called without any parameters. But in our program we have code only for the
constructor with parameters. Try executing this program and you will get an
error saying that method yyy takes 0 arguments. This is because we do not have
code for the constructor without parameters.
Let's understand the reason behind the error.
In our earlier programs, we did not specify a constructor. A
relevant question here would be - how did the objects get created then, without
the constructor being called? C# is a Good Samaritan, at that time it inserted
a free constructor. It does so internally. On its own it inserts a constructor
without any parameters, without any code into the class.
It looks like this-
yyy()
{
}
Point to ponder - in the above program, when we didn't
create a constructor without parameters why didn't we get one free? Remember we
said C# is a Good Samaritan? And Good Samaritans help the needy. On seeing that
we already have a constructor with parameters, C# looks the other way i.e., it
takes the free one away. However, it is only when you have no constructor at
all that C# melts its heart and gives you one free. Remember, even if it finds
that you have even one constructor it will take away the free one. On the assumption that if you can provide
one constructor, then with a little effort you can work towards providing the
others too!
Now the only way to get rid of the error is to add the
constructor yourself.
a.cs
class zzz
{
public static void Main()
{
yyy a,b;
System.Console.WriteLine("hi");
a=new yyy("no");
b=new yyy();
}
}
class yyy
{
public yyy(string s)
{
System.Console.WriteLine(s);
}
public yyy()
{
System.Console.WriteLine("bad");
}
}
Output
hi
no
bad
Here, initially, the two objects 'a' and 'b' are declared.
In the next statement we have WriteLine, which will display 'hi'. We are then
creating the object a. At this point the constructor with a string as a
parameter is called. It will now display the value stored in the variable s
which is 'no'. Thereafter, the object b is created. At this point the
constructor without the parameters will be called. This constructor contains
the WriteLine statement, which will print 'bad'. Here, we have as many
constructors as we are calling and hence we do not get any errors.
So, essentially, a constructor is a special function that
gets called when an object is created. It does not return any values, not even
void. As far as parameters go it behaves like a normal function. If no
constructors are specified you get one free, otherwise, you need as many
constructors as you are calling. Hence in the above case we cannot create an
object as new yyy(100) as we do not have a constructor that accepts one int as
a parameter.
Destructors
a.cs
public class zzz
{
public static void Main()
{
aa a = new aa();
}
}
public class aa
{
public aa()
{
System.Console.WriteLine("Constructor ");
}
~aa()
{
System.Console.WriteLine("Destructor");
}
}
Output
Constructor
Destructor
A destructor is a function with the same name as the name of
a class but starting with the character ~. A constructor gets called at birth
whereas a destructor gets called at death. In C# unlike other languages we do
not know when an object dies as unlike James Bond, we do not have a license to
kill. Thus even though the object a dies at the end of main, the destructor may
not get called. Thus, in C# we cannot decide when the destructor gets called.
This decision to call the destructor is made by a program within C# called the
garbage collector.
The concept first gained currency with the advent of Java.
In Java and C# we cannot remove our objects from memory. Thus it is for the
garbage collector to decide when to call the destructor. The programming world
was replete with errors mainly because programmers use new to allocate memory
and then forget to deallocate it. This gave rise to a concept called memory
leaks. On the flip side of the coin, programmers deallocated the memory, forgot
about it and then accessed the object again. This generates an error occurring
at random and difficult to pin down.
a.cs
public class zzz
{
public static void Main()
{
aa a = new aa();
}
}
public class aa
{
public aa()
{
System.Console.WriteLine("Constructor");
}
public ~aa()
{
System.Console.WriteLine("Destructor");
}
}
Compiler Error
a.cs(14,9): error CS0106: The modifier 'public' is not valid
for this item
A destructor cannot have any modifiers like public preceding
it.
a.cs
public class zzz
{
public static void Main()
{
aa a = new aa();
}
}
public class aa
{
public aa()
{
System.Console.WriteLine("Constructor");
}
~aa(int i)
{
System.Console.WriteLine("Destructor");
}
}
Compiler Error
a.cs(14,5): error CS1026: ) expected
a.cs(14,10): error CS1002: ; expected
a.cs(16,25): error CS1519: Invalid token '(' in class,
struct, or interface member declaration
a.cs(18,1): error CS1022: Type or namespace definition, or
end-of-file expected
Constructors come in plenty with different numbers of
arguments being passed to them. However, in the case of destructors, one size
fits all, i.e., they come in only one size, with no parameters. Here we created
a destructor with an int as a parameter thereby confusing the C# compiler
completely.
C# lacks true synchronous or deterministic destructors i.e.
destructors being called at a certain point in time. You cannot have your life
depend on when a destructor would be called. The common grouse against C# is
that unlike C++ it does not support true destructors.
a.cs
public class zzz
{
public static void Main()
{
aa a = new aa();
}
}
public class aa
{
public aa()
{
System.Console.WriteLine("Constructor");
}
~aa()
{
System.Console.WriteLine("Destructor");
}
protected override void Finalize()
{
}
}
Compiler Error
a.cs(18,25): error CS0111: Class 'aa' already defines a
member called 'Finalize' with the same parameter types
We tried to create a function called Finalize. The compiler
comes back and tells us that we already have a function called Finalize. This
is weird as we have only one Finalize function. The reason for this error is that
the compiler converts our destructor from
~aa to Finalize.
Arrays
All programming languages embrace the concept of arrays. An
array is nothing but more of one entity i.e., a multiple of the same type.
Simply put, when we have five books, we don't just say we have five books.
Instead we say we have an array of five books. So, whenever you want to store
multiple values of variables you store them in an array.
a.cs
class zzz
{
public static void Main()
{
int[] a;
a= new int[3];
a[0]= 1; a[1]= 10; a[2]= 20;
System.Console.WriteLine(a[0]);
a[0]++;
System.Console.WriteLine(a[0]);
int i;
i=1;
System.Console.WriteLine(a[i]);
i=2;
System.Console.WriteLine(a[i]);
}
}
Output
1
2
10
20
Here 'a' is an array of ints. You declare arrays with a set
of [] brackets. At this point it is not known how large the array will be. For
that we have a=new int[3]; after new we have int meaning we want to create a
variable of type int. We are putting 3 in the square brackets meaning we want
to store 3 ints. This will create three ints a[0], a[1] and a[2]. They are then
initialized to the values 1,10 and 20 respectively. To initialize an array
variable we use the name, i.e. in this case a and follow it with the open and
close [] brackets. Inside them we put the array number. The first variable is
called a[0] , the second a[1] and so on. C# like most computer programming
languages likes to start counting from 0 and not 1. Therefore, the last
variable is a[2] and not a[3].
Since an array is many of the same type, they all have the
same name. In our earlier example, even if we have many books, all the books
will be called books. However, to refer to them individually you can say book1,
book2, book3 etc.
WriteLine will display the value stored in a[0] which is 1.
a[0]++ will increment the value stored in a[0] by one. WriteLine will now
display 2.
Thereafter, the variable i is declared as an int. It is then
initialized to 1. Within the WriteLine function we have a[i]. It is not
specifically stated which variable, instead we have said a[i]. There is no
variable called a[i], but i has a value 1, so it is read as a[1]. Hence the
value stored at a[1], which is 10, is displayed. The next WriteLine will
display the value stored in a[2] as i is reinitialized to 2.
Doing this makes our program more generic. We haven't
specifically stated which variable, we are letting a variable called i decide
the name of the variable.
The next example demonstrates how arrays can be used within
loops.
a.cs
class zzz
{
public static void Main()
{
int[] a;
a= new int[3];
int i;
for( i=0; i<=2; i++)
a[i]= i*10;
for( i=0; i<=2; i++)
System.Console.WriteLine(a[i]);
}
}
Output
0
10
20
The advantage of using arrays is that you can decide the
name of the variable later and they can also be used in loops.
Here 'a' is an array of ints and i is a variable of type
int. The array size is 3 i.e. it can store three ints. The first for loop is used
to initialize the individual array items. Within the for loop, i is initialized
to 0. The condition i<=2 indicates that the loop will execute thrice. So,
when the control enters the for loop, for the first time i is 0. Looking at the
right hand side of the expression, i*10 will now read as 0*10, which is 0.
Hence, a[i] which is read as a[0] will be initialized to 0. i++ increments the
value of i to 1. The second time a[i] will be read as a[1] which will be
initialized to 10. Thereafter, a[i] will be read as a[2] and initialized to 20
as i is now 2. Now i will be 3, so the condition evaluates to false and the
loop terminates.
The second for loop displays the values stored in the array.
This is similar to the above loop. Here we are displaying the values of the
individual array items. As the for loop executes, WriteLine will read a[i] as
a[0], a[1] and a[2] in each case. As such, WriteLine displays 0,10,20. So,
starting from the beginning and going upto the end, all the values stored in
the array are displayed.
Arrays can also be used in a foreach statement. This is
exemplified in the following program.
a.cs
class zzz
{
public static void Main()
{
int[] a;
a= new int[3];
a[0]= 1; a[1]= 10; a[2]= 20;
foreach ( int i in a)
System.Console.WriteLine(i);
}
}
Output
1
10
20
The foreach statement lists the elements of the array. It
executes a statement for each element of the array or collection. 'a' is an
array of type int that can store three items. a[0], a[1] and a[2] are the
elements or items of the array. They have been initialized to 1, 10 and 20
respectively. In the foreach statement we have ( int i in a ).
i is a variable of type int and a is the array created
earlier. The first element of the array 'a' is a[0] and it holds the value 1.
The foreach statement picks up this value and stores it in i. Since i now holds
the value 1, WriteLine displays 1. The second element is a[1]. It picks up its
value, which is 10 and stores it in i. Thus i now holds the value 10. WriteLine
will now display 10. This goes on for all the elements of the array. Our array
'a' comprises three elements. Hence the foreach will execute the WriteLine
statement for each of them and display their values 1,10 and 20. The variable i
is only available in the foreach. The foreach makes it easier for us to run
through all the members of any array.
Parameters Revisited with Out and Ref
Variables are the cornerstone of programming languages. In a
way, they are like items contained in a bag. You can put an item in a bag,
remove it therefrom, or replace it with another. Our next few programs shall be
explained along these lines.
a.cs
class zzz
{
public static void Main()
{
int i=100;
yyy a;
a=new yyy();
a.abc(i);
System.Console.WriteLine(i);
}
}
class yyy
{
public void abc(int i)
{
System.Console.WriteLine(i);
i=10;
}
}
Output
100
100
'a' is an object that looks yyy. The variable 'i' is
initialized to a value 100. Then the object 'a' that looks like yyy is created.
We are now calling the function abc with one parameter 'i'. Within the abc
function we are printing the value of i. When we call the function abc from
Main, i had a value 100. So the variable i in abc also has a value 100. Thus
WriteLine will display the value 100. We are now assigning i a new value 10.
But the i that changes is the parameter i in abc, and not the i of Main in zzz.
It's like having two similar bags, where you change the contents of only one.
So the WriteLine in Main will again print 100.
Thus the variable i within the abc function is temporary. It
exists only within the '{' and '}' braces of the function. Therefore, this 'i'
is local to the function. Its value is not available in Main. It's like your
memory, temporary. It exists as long as you are reading this book. Once the
book is over everything is forgotten! Thus please do not call the variable i in
abc as i because it will confuse everyone. Thus i in abc has nothing to do with
the i in Main. Ergo, changing i in abc will have no effect on the i in Main.
But a situation could arise wherein you would like the
function abc to change the value of i. In this context you are saying, I am
giving a variable to a function abc, use it, but I would also like the function
abc to change it. And once its value is changed in the function, it i.e. the
changed value should be available in Main. Let's see how we can handle a
situation like that.
a.cs
class zzz
{
public static void Main()
{
yyy a;
int i=100;
a=new yyy();
a.abc(i);
System.Console.WriteLine(i);
}
}
class yyy
{
public void abc( out int i)
{
i=10;
}
}
Compiler Error
a.cs(8,1): error CS1502: The best overloaded method match
for 'yyy.abc(out int)' has some invalid arguments.
a.cs(8,7): error CS1503: Argument '1':cannot convert from
'int' to 'out int'.
This program is exactly like the previous one. The only
change is that we added the word 'out' in the function abc along with the
parameter i. We get an error on compiling this program. You realize, we are
saying a.abc(i) in Main, but in the function we are saying abc(out int i).
'out' is the key to solving our previous problem. 'out' means whatever changes
you will make in abc, they will be visible outside the function also.
Note that it doesn't matter what you call the variable in
the function abc, the original will change. So, instead of saying abc(out int
i) you could have used another variable. In that case, if you said abc(out int
p) it would be absolutely legal. To do away with the error you must specify
'out' while calling the function as well.
Now we have rewritten the program with the above change.
a.cs
class zzz
{
public static void Main()
{
yyy a;
int i=100;
a=new yyy();
a.abc(out i);
System.Console.WriteLine(i);
}
}
class yyy {
public void abc( out int i) {
i=10;
}
}
Output
10
In this program, we now have 'out' in both cases: in the
function call and the function itself.
So by saying a.abc( out i) you are implying that you are allowing the
function abc to change the value of i. Then in the function definition we also
have the word 'out', so it knows i is going to change and hence i now changes
in the original. Therefore, WriteLine will displays the new value 10.
We are now using the word 'ref' instead of 'out'. Let us see
the effects of doing so.
a.cs
class zzz
{
public static void Main()
{
yyy a;
int i=100;
a=new yyy();
a.abc(ref i);
System.Console.WriteLine(i);
}
}
class yyy
{
public void abc( ref int j)
{
j=10;
}
}
Output
10
This program executes smoothly and gives the same output as
previously. It displays the value 10. So in that sense 'ref' is like 'out'. In
either case the original value of 'i' changes. Thus, if you are calling the
function with 'ref' then state 'ref' in the function also. If you are calling
the function with 'out' then give 'out' in the function also.
Game for some experimentation? Let's try to execute the
above program without initializing the variable i.
a.cs
class zzz
{
public static void Main()
{
yyy a;
int i;
a=new yyy();
a.abc(ref i);
System.Console.WriteLine(i);
}
}
class yyy
{
public void abc(ref int j)
{
j=10;
}
}
Compiler Error
a.cs(8,11): error CS0165: Use of unassigned local variable
'i'
Here we are saying int i. Note that we are not
initializing i. We are using 'ref' which gives us an error. The error says 'use
of possibly unassigned local variable i'. Here we didn't initialize i and yet
we are trying to use it; hence we get an error.
Now, let's look at the next example. Here we have the same
program only now we are using 'out' instead of ref.
a.cs
class zzz
{
public static void Main()
{
yyy a;
int i;
a=new yyy();
a.abc(out i);
System.Console.WriteLine(i);
}
}
class yyy
{
public void abc(out int j)
{
j=10;
}
}
Output
10
In this program we haven't initialized i either but this
time we don't get any error. This goes to show that when using 'ref' the
variable must be initialized and only then can you change its value. In case of
'out' you don't have to initialize the variable to change its value.
But why have this differentiation? This is because in case
of 'ref' you can read the value of the variable as well as write to it.
Therefore, if one has to read the value of the variable, it must be initialized
before hand. But it is your discretion whether you want to change the value,
read it or do both.
But in case of 'out' you can only write i.e., you can only
change the value of the variable, you cannot read it. So, in case of 'out'
since it does not read the variable it doesn't matter even if it is not
initialized.
This is further exemplified with the help of the next few
programs. In the following program we have initialized i. Note here we are
using 'out'.
a.cs
class zzz
{
public static void Main()
{
yyy a;
int i=10;
a=new yyy();
a.abc(out i);
System.Console.WriteLine(i);
}
}
class yyy
{
public void abc( out int j)
{
System.Console.WriteLine(j);
j=10;
}
}
Compiler Error
a.cs(16,26):error CS0165: Use of unassigned local variable
'j'
Within the function abc we are first printing the value of i
using the WriteLine statement. That means we are trying to read the value of i
which is passed to the variable j in the function abc. But with 'out' one
cannot read values hence we get an error. Now if you try the same program with
'ref' instead of 'out' you will not get any errors. This is because with 'ref'
you can read the values as well as well as change them.
However do note that all 'out' parameters must be
initialized or else you will get an error form the compiler as follows.
a.cs
class zzz
{
public static void Main()
{
yyy a;
int i=10;
a=new yyy();
a.abc(out i);
System.Console.WriteLine(i);
}
}
class yyy
{
public void abc( out int j)
{
}
}
Compiler Error
a.cs(14,13): error CS0177: The out parameter 'j' must be
assigned to before control leaves the current method
So where can we use 'out'? We can use 'out' if we want the
function to make some calculations and fill up the variable.
a.cs
class zzz
{
public static void Main()
{
yyy a;
int i=10;
a=new yyy();
a.abc( out i );
System.Console.WriteLine(i);
}
}
class yyy
{
public void abc( out int i )
{
i= 20 * 20;
}
}
Output
400
In this program we are using 'out'. We are multiplying 20 by
20 and storing the result 400 in i. Thereby the value of i is changed and
WriteLine will now print 400.
Our next example will make things as clear as daylight.
a.cs
class zzz
{
public static void Main()
{
yyy a;
int i=10;
int k=20;
int m;
a=new yyy();
m=a.abc( out i, out k );
System.Console.WriteLine(i);
System.Console.WriteLine(k);
System.Console.WriteLine(m);
}
}
class yyy
{
public int abc( out int x, out int y)
{
int j;
x=30;y=10;
j=x * y;
return j;
}
}
Output
30
10
300
After specifying that a looks like yyy, the two variables i
and k are initialized to the values 10 and 20 respectively. Then the object a
is created. The third variable m is of type int and is used to store the return
value of the function abc. By using 'out', the function abc is called with two
parameters, i and k. The abc function has the variables x and y. Within the
function another variable j is declared of type int. The variables x and y are
assigned new values 30 and 10 respectively. Their values are multiplied and
stored in j, i.e. 300. The next statement return j will yield the value of j,
which is stored in m. Now WriteLine will display the value of i as 30. This is
because with the abc function we filled up i with the value 30. Similarly, the
next WriteLine statement will print the value of k, which is 10. Then we print
the value of m, which is 300.
In a nutshell-
In case of both 'ref' and 'out' the original changes.
A point to note is that when we say 'ref' it means we will
initialize the variable. The abc function expects the variable to be
initialized so that the function can use the value of the variable. When the
variable changes the change is reflected outside. So, whenever you say 'ref'
the variable has to be initialized, otherwise an error occurs. The function
will assume that the variable is initialized because it expects to read the
value. You may choose to read the value or change it or do both.
But when you say 'out' it implies that we are not going to initialize the variable, that the abc function is not going to use the value, it is only going to change the value. When there is an 'out', abc can use the variable even if it is not initialized. This is because you cannot read the value in case of an 'out' variable; the function can only change the value. In other words, it has to change the value of the variable to avoid any errors.