tags:

views:

1234

answers:

9

What is the object life cycle for an object in .NET?

From what I understand it is:

  1. Object created - constructor called (if one exists)
  2. Methods/Properties/Fields used
  3. Object destroyed - Dispose called (if one exists)
  4. Destructor called by GC at some point
+18  A: 

Dispose doesn't get called automatically; you need to call it, or use a using block, eg.

using(Stream s = File.OpenRead(@"c:\temp\somefile.txt"))
    // Do something with s

The finalizer only gets called by the GC if it exists. Having a finalizer causes your class to be collected in 2 steps; first the object is put in the finalizer queue, then the finalizer is called and the object is collected. Objects without finalizers are directly collected.

The guideline is that Dispose gets rid of managed and unmanaged resources, and the finalizer only cleans up unmanaged resources. When the Dispose method has freed the unmanaged resources it can call GC.SuppressFinalize to avoid the object from living long to be put on the finalizer queue. See MSDN for a correct sample of the dispose pattern.

Sander Rijken
+11  A: 

Just as an edge case... you can create objects without using the ctor at all:

class Foo {  
    public Foo() {
        message += "; ctor";
    }
    string message = "init";
    public string Message { get { return message; } }
}
static class Program {
    static void Main() {
        Foo foo = new Foo();
        Console.WriteLine(foo.Message); // "init; ctor"
        Foo bar = (Foo)System.Runtime.Serialization.FormatterServices
            .GetSafeUninitializedObject(typeof(Foo));
        Console.WriteLine(bar.Message); // null
    }
}
Marc Gravell
Not that I can see when you would or should use this but +1 for teaching me something cool.
rein
This is mainly used by BinaryFormatter during deserialization
Marc Gravell
+5  A: 

Here is a detailed descriptin of the question. First, Dispose is not called by runtime, you have to call it yourself. There are also no destructors, but finalizers: if an object overrides a Finalized method, it is called when the object is no longer accessible for the application. It may happen that during finalization the object becomes accessible again (for example, stores a reference to itself in a global object), so it returns to step 2 of your model. There are also methods in GC object that let the user control object finalization.

Dmitry Risenberg
I thought that finalizers are not allowed to touch managed space anymore. At least that was my reading of the official IDispose pattern, which specifically separates between managed and unmanaged resources for the finalizer.
David Schmitt
They can, but just don't do that. See http://blogs.msdn.com/clyon/archive/2006/04/25/583698.aspx
Sander Rijken
Thanks, that was a very interesting read.
David Schmitt
+6  A: 

Here are the steps I know of:

  1. load the assembly
  2. execute static initialisers
  3. "new" call:
    1. allocate memory
    2. execute non-static initialisers
    3. execute constructor
  4. the instance is now ready to be used
  5. after the last reference to the object has vanished: if the object has no finalizer, it is now ready for collection; if the object has a finalizer, it is put on the finalizer queue.
  6. (optional) the objects from the finalizer queue have their finalizer called in a special thread; if there is still no reference from the application to the object, it too becomes now eligible for garbage collection
  7. the garbage collector deallocates memory

As others already have pointed out, Dispose() must be called by the user since the runtime won't act on it.

David Schmitt
Should point out that if the finalizer takes too long to run the thread will be aborted without any notification or thrown exceptions
Matthew Whited
static constructors are not necessary initialized in this order. I think the only guarantee is that they are called before accessing static variables in that class.. But that can be after the constructor.
Bert Huijben
http://msdn.microsoft.com/en-us/library/k9x6w0hc.aspx states explicitly: "called automatically before the first instance is created or any static members are referenced"
David Schmitt
+1  A: 

A point about the constructor:

Every class has one, as one will be generated by the compiler if you don't code it yourself. And the first thing this does (unless specified otherwise), is to call the ctor of it's parent type.

Hans Kesting
A: 

This article on Garbage Collection should help you get a better understanding:

http://www.c-sharpcorner.com/UploadFile/DipalChoksi/UnderstandingGarbageCollectioninNETFramework11292005051110AM/UnderstandingGarbageCollectioninNETFramework.aspx

Chris Pietschmann
It's probably better for the site layout if you hook up that long url to something like [this article] :-)
Sander Rijken
+1  A: 

0) If Static Constructor exists on Object it is called the first time and object of that type is created or referenced

Matthew Whited
A: 

In C#, member initializers are called before the constructor while in VB.NET, they are called after the constructor.

The runtime does not guarantee calling Finalize at all.

Dispose and Finalize is for cleaning up unmananged resources only. Trying to clean up managed resources in a finalizer by e.g. calling Dispose on inner members will land you in trouble because they may have been finalized already.

I like to keep things simple and just use the finalizer to detect and log a nasty error message telling the developer to go fix the code. Trying to figure out whether it is safe to do the work Dispose was supposed to do is too easy to get wrong and usually not worth spending cycles on.

Hans Malherbe
+1  A: 

Here is an example class that uses all the information available in the articles provided here. I have already spent hours testing things out, and this is what works best for me.

/*********************************
 * Author:  Theofanis Pantelides *
 *   Date:  23 Jun 2009          *
 *********************************/

using System;
using System.IO;

public class MyClass : IDisposable
{
    String oFile;
    Stream oStream;

    public MyClass(String _File)
    {
        oStream = File.OpenRead(oFile = _File);
        // Initialize
    }

    ~MyClass()
    {
        this.Dispose();
        // Destruct
    }

    public void doSomething()
    {
        // do Whatever it is you are trying to do
    }

    #region IDisposable Members

    /// <summary>
    /// Dispose all resources used by instance of class
    /// and update Garbage Collector information
    /// </summary>
    public void Dispose()
    {
        if (oStream != null)
        {
            oStream.Dispose(); // Dispose using built in functions
            GC.SuppressFinalize(oStream); // No need for Garbage Collector
        }

        oStream = null;  // Nullify it.
    }

    #endregion
}

Usage:

using(MyClass mc = new MyClass(@"c:\temp\somefile.txt"))
{
  mc.doSomething();
}

You can even use the same declaration twice as it does not exist outside the 'using'.

using(MyClass mc = new MyClass(@"c:\temp\somefile.txt"))
{
  mc.doSomething();
}

using(MyClass mc = new MyClass(@"c:\temp\somefile.txt"))
{
  mc.doSomething();
}
Theofanis Pantelides
If you want one class to explain the entire life cycle you should add a static field and static constructor as well.
Matthew Whited