Reference Types vs. Value (Simple) Types

advertisement
Review: References
The goal for this exercise is to make sure that you can use the material that has
been covered in the previous exercises, but in a more open-ended (and therefore
more ‘real-world’-like) scenario
Thus far, you've seen both reference types, and what are known as simple
types.
 A simple type is something like an int, a double, or a System.DateTime structure.
Conceptually, these types are used primarily to store data, although they might also
have methods attached to them.
While we won't be doing this quite yet, it's possible for us to create new simple types
using the struct keyword (in place of the class keyword).
 This is substantially different from reference types, which include all classes that
you've ever created, and arrays. Classes are intended to hold not just data, but also
express inheritance relationships between classes, and generally form the
'framework' for an application by connecting together multiple instances of multiple
classes.
Further, there are a number of other differences, which are summarized below. The
project that was used to generate these examples is also available as a project within
the starter solution that was provided for this lesson (The project is named
ReferencesExample
)
You may find it useful to search the web for more information. In particular, this
website
(http://www.csharpcorner.com/UploadFile/rmcochran/csharp_memory01122006130034PM/csharp_
memory.aspx?ArticleID=9adb0e3c-b3f6-40b5-98b5-413b6d348b91 ) seems to be
fairly informative about the differences between memory allocated on the call stack vs.
memory allocated in the heap.
Simple types vs. reference types
Always copied by value
// create a space in memory to hold
// an integer
int anInteger;
// create another space in memory
// to hold an integer
int anotherInteger;
anInteger = 0;
anotherInteger = 10;
// Integers are initialized
anInteger = anotherInteger;
// There are now two memory spaces
// the number 10 in each one
Always copied by reference
// create a space in memory to hold
// a refernce to a ProgramLogic
// NOTE: WE HAVEN'T CREATED THE
// PROGRAMLOGIC OBJECT YET!!!
ProgramLogic pl1;
// create another space in memory to hold
// a refernce to a ProgramLogic
// NOTE: WE HAVEN'T CREATED THE
// PROGRAMLOGIC OBJECT YET!!!
ProgramLogic pl2;
pl1 = new ProgramLogic();
pl2 = new ProgramLogic();
// Initialize the references - they
// now each refer to a separate instance
//
//
//
//
//
//
//
of the ProgramLogic class.
Thus, we've got FOUR blocks of memory
being used
#1 for pl1
#2 for the ProgramLogic that pl1 refers to
#3 for pl2
#4 for the ProgramLogic that pl2 refers to
pl1 = pl2;
// pl1 & pl2 now refer to the same object
// the object pl1 WAS refering to will be
// garbage collected (unless something else is
// still refering to it) since pL1 now points
// to the same object as pl2.
Always passed by value
class SimpleVsReference
{
static void Main()
{
// SIMPLE TYPES ARE PASSED BY VALUE
// (to methods):
int theNum = 0;
Console.WriteLine("Prior to calling
the function: {0}", theNum);
PassByValue(theNum);
Console.WriteLine("After to calling
the function: {0}", theNum);
}
Always passed by reference
class SimpleVsReference
{
static void Main()
{
// REFERENCE TYPES ARE PASSED BY
// REFERNCE (to methods):
ProgramLogic pl = new ProgramLogic();
// pl has been created, AND we've create an
// object of type ProgramLogic
// for it to refer to. ProgramLogic's
// constructor
// initialized the new object to contain 0
Console.WriteLine("Prior to calling the
function: {0}", pl.ToString() );
PassByRef(pl);
Console.WriteLine("After to calling the
function: {0}", pl);
// This last time, we left off the
"ToString", since C# will
// call that for us.
}
public
{
//
//
//
//
//
static void PassByValue(int x)
at this point, there's now two
blocks of memory holding
the value 0. They are:
theNum (in main)
x (in this method - PassByValue)
Console.WriteLine("Passed in: {0}", x);
// let's try to change it
x = 10;
public static void PassByRef(ProgramLogic obj)
{
Console.WriteLine("Passed in: {0}",
obj.ToString());
// let's try to change it
obj.Data = 10;
Console.WriteLine("Changed to: {0}",
obj.ToString());
}
}
Console.WriteLine("Changed to: {0}",x);
}
}
OUTPUT:
Prior to calling the function: 0
Passed in: 0
Changed to: 10
After calling the function: 0
OUTPUT:
Prior to calling the function: ProgramLogic
object containing: 0
Passed in: ProgramLogic object containing: 0
Changed to: ProgramLogic object containing: 10
After calling the function: ProgramLogic object
containing: 10
Always has a valid value
// SIMPLE TYPES ALWAYS HAVE A VALID VALUE
int integer; // technically, C# has
// initialized this with a 'zero'
// However, we're not allowed to
// use it before assigning it
// a value
integer = 0; // 0 is a valid integer
Console.WriteLine("integer: {0}",
integer);
integer = 10; // 10 is a valid integer
Console.WriteLine("integer: {0}",
integer);
integer = -10; // -10 is a valid integer
Console.WriteLine("integer: {0}",
integer);
OUTPUT:
integer: 0
integer: 10
integer: -10
OUTPUT FROM RIGHT COLUMN:
theLogic:
theLogic is null!
ProgramLogic object containing: 0
May be null, indicating that there's no currently valid
reference.
//
//
//
//
//
//
REFERENCES MAY OR MAY NOT HAVE A VALID VALUE
References either refer to an object
(and instance of a class), or else
they can have the value null,meaning
that the reference is NOT VALID (i.e.,
it doesn't refer to a valid object)
ProgramLogic theLogic; // technically, this
// has the value null, but still needs
// to be assigned a value before use
theLogic = null;
// theLogic now refers to nothing
//
//
//
//
//
//
If we attempt to dereference it, the program
will crash
To dereference theLogic, we try to get to
one of it's parts - data, property,
or method - using the dot operator:
theLogic.Data = 0; // uncomment this line
// & see what happens
// Console.WL is smart enough
// to check for null:
Console.WriteLine("theLogic: " + theLogic);
if (null == theLogic)
{
Console.WriteLine("theLogic is null!");
}
else
{
Console.WriteLine("theLogic is NOT null: "
+ theLogic);
}
// We can reuse the REFERENCE, so that
// it now refers to something else:
theLogic = new ProgramLogic();
// theLogic now refers to a new object
// of type ProgramLogic
theLogic.Data = 0;
Console.WriteLine(theLogic);
What you need to do for this exercise:
For this exercise, you're not required to produce anything, but you are required
to read this material (including, and especially, the code examples) in detail, and to
understand them. The most important part is probably the section on how reference
variables can have the value null, indicating that the reference is not valid.
I'd recommend examining the sample project, and playing around with the code
(for example, stepping through the examples using the debugger, tweaking the code
to achieve different results, etc, etc)
In a future lesson, you'll see how to create your own value types / simple types
(called structs), and so it's important to start building up an understanding of how they
differ from classes (from reference types), so you can hit the ground running at that
point.
Download