Deferred Object Instantiation in C#

If a class declaration contains object members, the members are typically assigned and instantiated in a constructor or in the class definition:

public class Foo
{
  private Bar bar = new Bar();
  private Baz baz;

  public Foo(int ID)
  {
    baz = new Baz(ID);
  }
}

If the instantiation of member objects is costly, e.g. when fetching records from a database, deferred instantiation might be preferred, especially if it is not certain that the object actually needs to be instantiated.

This led me to the creation of a generic DeferredObject class, the constructor of which is passed a function or delegate to fetch the data in case it is needed:

public class DeferredObject<T>
{
  public delegate TT DeferredObjectFetcher<TT>();

  public DeferredObject(DeferredObjectFetcher<T> Fetcher)
  {
    this.Fetcher = Fetcher;
  }

  private DeferredObjectFetcher<T> Fetcher;
}

The fetch operation (to instantiate the object) is invoked the first time the object’s Value property is invoked:

  private bool Fetched;
  private T _Value;

  public T Value
  {
    get
    {
      if (!Fetched)
      {
        _Value = Fetcher();
        Fetched = true;
      }
      return _Value;
    }
  }

An implicit type conversion operator can be useful, e.g. to compare an int to a DeferredObject without explicitly using the .Value method. The ToString() method redirects to the ToString() of the Value:

  public static implicit operator T(DeferredObject<T> co)
  {
    return co.Value;
  }
  public override string ToString()
  {
    return Value.ToString();
  }

Finally, allow the DeferredObject to be reset and re-instantiated on demand:

  public void Clear()
  {
    Fetched = false;
    _Value = default(T);
  }

Rewriting the original sample code to use the DeferredObject solution:

public class Foo
{
  private Bar bar = new DeferredObject<Bar>(delegate() { return new Bar(); });
  private Baz baz;

  public Foo(int ID)
  {
    baz = new DeferredObject<Baz>(delegate() { return new Baz(ID); });
  }
}

DeferredObjects may of course depend on other DeferredObjects:

  baz = new DeferredObject<Baz>(delegate() { return new Baz(ID); });
  bar = new DeferredObject<Bar>(delegate() { return new Bar(Baz.Value.BarID); });

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: