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.