In C#, automatic memory management is provided so that developers are freed from this burdensome task. In the vast majority of cases, automatic memory management increases code quality and enhances developer productivity without negatively impacting either expressiveness or performance.
The example
public class Stack
{
private Node first = null;
public bool Empty
{
get
{
return (first == null);
}
}
public object Pop()
{
if (first == null)
{
throw new Exception("Can't Pop from an empty Stack.");
}
else
{
object temp = first.Value;
first = first.Next;
return temp;
}
}
public void Push(object o)
{
first = new Node(o, first);
}
class Node
{
public Node Next;
public object Value;
public Node(object value): this(value, null) {}
public Node(object value, Node next)
{
Next = next;
Value = value;
}
}
}
shows a Stack class implemented as a linked list of Node instances. Node instances are created in the Push method and are garbage collected when no longer needed. A Node instance becomes eligible for garbage collection when it is no longer possible for any code to access it. For instance, when an item is removed from the Stack, the associated Node instance becomes eligible for garbage collection.
The example
class Test
{
static void Main() {
Stack s = new Stack();
for (int i = 0; i < 10; i++)
s.Push(i);
s = null;
}
}
shows code that uses the Stack class. A Stack is created and initialized with 10 elements, and then assigned the value null. Once the variable s is assigned null, the Stack and the associated 10 Node instances become eligible for garbage collection. The garbage collector is permitted to clean up immediately, but is not required to do so.
But sometimes developers need fine-grained control or extra bit of performance, C# provides a mechanism to do this: using statement. The syntax of using statement is:
using (Resource r = new Resource())
{
r.F();
}
To take advantage of early disposal, the class delcared in using statement must be a resource. A resource is a class or struct that implements System.IDisposable, which includes a single parameterless method named Dispose.
Code that is using a resource can call Dispose to indicate that the resource is no longer needed. If Dispose is not called, then automatic disposal eventually occurs as a consequence of garbage collection.
When the end of the using statement block is reached, the resource object's Dispose() method will be immediately called. This is extremely useful when we need to release a resource intensive object, like a database connection object or file handle.
using (SqlConnection conn = new SqlConnection(connString))
{
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "SELECT * FROM DEPT";
conn.Open();
....
}
Local resource variables declared in a using statement are read-only, and must include an initializer. A compile-time error occurs if the embedded statement attempts to modify these local variables (via assignment or the ++ and -- operators) or pass them as ref or out parameters.