When you declare an int variable, the compiler generates code that allocates a block of memory big enough to hold an integer.. When you declare a Circle variable, the compiler does not g
Trang 1Copying int Variables and Classes
All primitive types such as int are called value types When you declare an int variable, the compiler generates code that allocates a block of memory big enough to hold an integer A statement that assigns a value (such as 42) to the int causes the value to be copied to this block of memory
Class types, such as Circle (described in Chapter 7), are handled differently When you declare a Circle variable, the compiler does not generate code that allocates a block of memory big enough to hold a Circle; all it does is allot a small piece of memory that can potentially hold the address of (or a reference to) another block of memory containing a Circle The memory for the Circle object itself is only allocated when the new keyword is used to create the object
This demonstrates that value types are so called because they hold values directly
Reference types (such as classes) hold references to blocks of memory
NOTE
If you are a C or C++ programmer you might be tempted to think of reference types simply as pointers While reference types in C# exhibit many similarities to pointers, they provide far more functionality For example, in a C or C++ application it is possible to make a pointer reference almost any block of memory regardless of the type of data the block is holding Sometimes this is useful, but more often than not it is the cause of many insidious programming errors In C#, all references are strongly typed; you cannot
declare a reference variable that refers to one type (such as Circle), and then use the variable to access a block of memory holding a different type There are other differences
as well, concerning the way in which the common language runtime manages and
reclaims memory These features are discussed in Chapter 13, “Using Garbage Collection and Resource Management.”
Because of the different ways that they hold data, value types are sometimes called direct types, and reference types are sometimes called indirect types You need to fully
understand the difference between value types and reference types
Consider the situation where you declare a variable named i as an int and assign it the value 42 If you declare another variable copyi as an int, and initialize or assign copyi to
i, copyi will hold the same value as i (42) However, the fact that copyi and i happen to hold the same value does not alter the fact that there are two copies of the value 42: one inside i and the other inside copyi If you modify the value in i, the value in copyi does not change Let's see this in code:
Trang 2int i = 42;// declare and initialize i
int copyi = i;// copyi contains a copy of the data in i
i++;// incrementing i has no effect on copyi
The effect of declaring c as a Circle (the name of a class) is very different When you declare c as a Circle, c can refer to a Circle object If you declare refc as another Circle, it can also refer to a Circle object If you choose to initialize or assign refc to c, refc will refer to the same Circle object that c does; there is only one Circle object, and refc and c both refer to it Let's see this in code:
Circle c = new Circle(42);
Circle refc = c;
The following graphic illustrates both examples:
The difference explained above is very important In particular, it means that the behavior
of method parameters depends on whether they are value types or reference types You'll explore this difference in the following exercise
Use value parameters and reference parameters
1 Start Microsoft Visual Studio 2005
2 Open the Parameters project, located in the \Microsoft Press\Visual CSharp Step
by Step\Chapter 8\Parameters folder in your My Documents folder
3 Display the Pass.cs source file in the Code and Text Editor window Locate the Pass class Add a public static method called Value to the Pass class This method should accept a single int parameter (a value type) called param and have a return type of void The body of Value should simply assign 42 to param
The Pass class should look exactly like this:
namespace Parameters
{
class Pass
{
public static void Value(int param)
{
param = 42;
}
}
}
Trang 34 Display the Program.cs source file in the Code and Text Editor window, and then locate the Entrance method of the Program class
The Entrance method is called by the Main method when the program starts
running As explained in Chapter 7, the method call is wrapped in a try block and followed by a catch handler
5 Add four statements to the Entrance method to perform the following tasks:
1 Declare a local int variable called i and initialize it to 0
2 Write the value of i to the console by using Console.WriteLine
3 Call Pass.Value, passing i as an argument
4 Write the value of i to the console again
The calls to Console.WriteLine before and after the call to Pass.Value allow you
to see whether the call to Pass.Value actually modifies the value of i The Entrance method should look exactly like this:
static void Entrance()
{
int i = 0;
Console.WriteLine(i);
Pass.Value(i);
Console.WriteLine(i);
}
6 On the Debug menu, click Start Without Debugging to build and run the program
7 Confirm that the value of 0 is written to the console window twice
The assignment inside Pass.Value was made by using a copy of the argument, and the original argument i is completely unaffected
8 Press the Enter key to close the application
You will now see what happens when you pass an int parameter that is wrapped inside a class
9 Display the WrappedInt.cs source file in the Code and Text Editor window Add a public instance field called Number of type int to the WrappedInt class
The WrappedInt class should look exactly like this:
namespace Parameters
{
class WrappedInt
Trang 4{
public int Number;
}
}
10 Display the Pass.cs source file in the Code and Text Editor window Add a public static method called Reference to the Pass class This method should accept a single WrappedInt parameter called param and have a return type of void The body of the Reference method should assign 42 to param.Number
The Pass class should look exactly like this:
namespace Parameters
{
class Pass
{
public static void Value(int param)
{
param = 42;
}
public static void Reference(WrappedInt param)
{
param.Number = 42;
}
}
}
11 Display the Program.cs source file in the Code and Text Editor window Add four more statements to the Entrance method to perform the following tasks:
1 Declare a local WrappedInt variable called wi and initialize it to a new WrappedInt object by calling the default constructor
2 Write the value of wi.Number to the console
3 Call the Pass.Reference method, passing wi as an argument
4 Write the value of wi.Number to the console again
As before, the calls to Console.WriteLine allow you to see whether the call to Pass.Reference modifies the value of wi.Number The Entrance method should now look exactly like this:
static void Entrance()
{
int i = 0;
Trang 5Console.WriteLine(i);
Pass.Value(i);
Console.WriteLine(i);
WrappedInt wi = new WrappedInt();
Console.WriteLine(wi.Number);
Pass.Reference(wi);
Console.WriteLine(wi.Number);
}
12 On the Debug menu, click Start Without Debugging to build and run the
application
As before, the first two values written to the console window are 0 and 0, before and after the call to Pass.Value For the next two values, which correspond to value wi.Number before and after Pass.Reference, confirm that the value of 0 and then the value of 42 are written to the console window
13 Press the Enter key to close the application
In the previous exercise, the value of wi.Number is initialized to 0 by the
compiler-generated code The wi variable contains a reference to the newly created WrappedInt object (which contains an int) The wi variable is then copied as an argument to the Pass.Reference method Because WrappedInt is a class (a reference type), wi and param both refer to the same WrappedInt object Any changes made to the contents of the object through the param variable in the Pass.Reference method are visible by using the wi variable when the method completes The following diagram illustrates what happens when a WrappedInt object is passed as an argument to the Pass.Reference method: