Understanding Reference Types
Reference type variables are named appropriately (reference) because the variable holds a reference to an object. In C and C++, you have something similar that is called a pointer, which points to an object. While you can modify a pointer, you can't modify the value of a reference - it simply points at the object in memory.
An important fact you need to understand is that when you are assigning one reference type variable to another, only the reference is copied, not the object. The variable holds the reference and that is what is being copied. Listing 22-2 shows how this works.
// Reference Type Assignment
using System;
class Employee
{
private string m_name;
public string Name
{
get { return m_name; }
set { m_name = value; }
}
}
class Program
{
static void Main()
{
Employee joe = new Employee();
joe.Name = "Joe";
Employee bob = new Employee();
bob.Name = "Bob";
Console.WriteLine("Original Employee Values:");
Console.WriteLine("joe = " + joe.Name);
Console.WriteLine("bob = " + bob.Name);
// assign joe reference to bob variable
bob = joe;
Console.WriteLine();
Console.WriteLine("Values After Reference Assignment:");
Console.WriteLine("joe = " + joe.Name);
Console.WriteLine("bob = " + bob.Name);
joe.Name = "Bobbi Jo";
Console.WriteLine();
Console.WriteLine("Values After Changing One Instance:");
Console.WriteLine("joe = " + joe.Name);
Console.WriteLine("bob = " + bob.Name);
Console.ReadKey();
}
}
Here's the output:
Original Employee Values:
joe = Joe
bob = Bob
Values After Reference Assignment:
joe = Joe
bob = Joe
Values After Changing One Instance:
joe = Bobbi Jo
bob = Bobbi Jo
4 most important questions in an interview
Pay close attention to those four most important questions they want answers to:
1. Why are you here?
2. What can you do for us?
3. Will you fit in? (Will you get along with our values and culture here?)
4. What makes you different from everyone else that we may have talked with? (Will you go that extra mile?)
Rehearse your answers with your own personal "stories." These are short narratives describing times when you overcame a crisis, led a team, met a deadline, resurrected a failed project, etc.
Some common questions you'll often encounter at the beginning of the interview:
"Tell me a little about yourself." (Question #2: "What can you do for us?")
"What do you know about us?" (Question #1: "Why are you here?")
"Why are you here today?" (Same)
"Why are you looking to change jobs?" (Question#2: "What can you do for us?")
"What's your most important accomplishment to date?" (Same)
Why should we hire you (over everyone else we've seen)? (Question #4: "Will you go the extra mile?")
Working with Dictionary Collections
Another very useful generic collection is the Dictionary, which works with key/value pairs. There is a non-generic collection, called a Hashtable that does the same thing, except that it operates on type object. However, as explained earlier in this lesson, you want to avoid the non-generic collections and use thier generic counterparts instead. The scenario I'll use for this example is that you have a list of Customers that you need to work with. It would be natural to keep track of these Customers via their CustomerID. The Dictionary example will work with instances of the following Customer class:
public class Customer
{
public Customer(int id, string name)
{
ID = id;
Name = name;
}
private int m_id;
public int ID
{
get { return m_id; }
set { m_id = value; }
}
private string m_name;
public string Name
{
get { return m_name; }
set { m_name = value; }
}
}
The Customer class above has a constructor to make it easier to initialize. It also exposes it's state via public properties. It isn't very sophisticated at this point, but that's okay because its only purpose is to help you learn how to use a Dictionary collection. The following example populates a Dictionary collection with Customer objects and then shows you how to extract entries from the Dictionary:
Dictionary
Customer cust1 = new Customer(1, "Cust 1");
Customer cust2 = new Customer(2, "Cust 2");
Customer cust3 = new Customer(3, "Cust 3");
customers.Add(cust1.ID, cust1);
customers.Add(cust2.ID, cust2);
customers.Add(cust3.ID, cust3);
foreach (KeyValuePair
{
Console.WriteLine(
"Customer ID: {0}, Name: {1}",
custKeyVal.Key,
custKeyVal.Value.Name);
}
What Can Generics Do For Me?
In .NET v1.0 there were collections, such as the ArrayList for working with groups of objects. An ArrayList is much like an array, except it could automatically grow and offered many convenience methods that arrays don't have. The problem with ArrayList and all the other .NET v1.0 collections is that they operate on type object. Since all objects derive from the object type, you can assign anything to an ArrayList. The problem with this is that you incur performance overhead converting value type objects to and from the object type and a single ArrayList could accidentally hold different types, which would cause a hard to find errors at runtime because you wrote code to work with one type. Generic collections fix these problems.
A generic collection is strongly typed (type safe), meaning that you can only put one type of object into it. This eliminates type mismatches at runtime. Another benefit of type safety is that performance is better with value type objects because they don't incur overhead of being converted to and from type object. With generic collections, you have the best of all worlds because they are strongly typed, like arrays, and you have the additional functionality, like ArrayList and other non-generic collections, without the problems.
Applying Generics
Because of the native support for generics in the IL and the CLR, most CLR-compliant language can take advantage of generic types. For example, here is some Visual Basic .NET code that uses the generic stack of Code block 2:
Dim stack As Stack(Of Integer)
stack = new Stack(Of Integer)
stack.Push(3)
Dim number As Integer
number = stack.Pop()
You can use generics in classes and in structs. Here is a useful generic point struct:
public struct Point
{
public T X;
public T Y;
}
You can use the generic point for integer coordinates, for example:
Point
point.X = 1;
point.Y = 2;
Or for charting coordinates that require floating point precision:
Point
point.X = 1.2;
point.Y = 3.4;
Besides the basic generics syntax presented so far, C# 2.0 has some generics-specific syntax. For example, consider the Pop() method of Code block 2. Suppose instead of throwing an exception when the stack is empty, you would like to return the default value of the type stored in the stack. If you were using an Object-based stack, you would simply return null, but a generic stack could be used with value types as well. To address this issue, you can use the default() operator, which returns the default value of a type.
Here is how you can use default in the implementation of the Pop() method:
public T Pop()
{
m_StackPointer--;
if(m_StackPointer >= 0)
{
return m_Items[m_StackPointer];
}
else
{
m_StackPointer = 0;
return default(T);
}
}
C# Topic: Generics Overview
Generics are the most powerful feature of C# 2.0. Generics allow you to define type-safe data structures, without committing to actual data types. This results in a significant performance boost and higher quality code, because you get to reuse data processing algorithms without duplicating type-specific code. In concept, generics are similar to C++ templates, but are drastically different in implementation and capabilities. This article discusses the problem space generics address, how they are implemented, the benefits of the programming model, and unique innovations, such as constrains, generic methods and delegates, and generic inheritance. You will also see how generics are utilized in other areas of the .NET Framework such as reflection, arrays, collections, serialization, and remoting, and how to improve on the basic offering.
Generics allow you to define type-safe classes without compromising type safety, performance, or productivity. You implement the server only once as a generic server, while at the same time you can declare and use it with any type. To do that, use the < and > brackets, enclosing a generic type parameter. For example, here is how you define and use a generic stack:
public class Stack
{
T[] m_Items;
public void Push(T item)
{...}
public T Pop()
{...}
}
Stack
stack.Push(1);
stack.Push(2);
int number = stack.Pop();