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.
No comments:
Post a Comment