TheDeveloperBlog.com


C# Lazy Example

Lazy instantiation delays certain tasks. It typically improves the startup time of a C# application. This has always been possible to implement. But the .NET Framework now offers the Lazy type, which provides this feature.


Example. To start, let's examine a simple example of the Lazy type. In this program, you will first see the Test class. This class contains a constructor and an allocation occurs in the constructor.

Constructor

In the Main entry point, a new Lazy instance of the Test type is created. The IsValueCreated property is False at this point. Then, when the Value property is accessed, the Test class constructor is executed and memory allocation occurs.

Finally: The IsValueCreated property returns True and the Test instance can be used like any other object.

Property
C# program that uses Lazy type

using System;

class Test
{
    int[] _array;
    public Test()
    {
	Console.WriteLine("Test()");
	_array = new int[10];
    }
    public int Length
    {
	get
	{
	    return _array.Length;
	}
    }
}

class Program
{
    static void Main()
    {
	// Create Lazy.
	Lazy<Test> lazy = new Lazy<Test>();

	// Show that IsValueCreated is false.
	Console.WriteLine("IsValueCreated = {0}", lazy.IsValueCreated);

	// Get the Value.
	// ... This executes Test().
	Test test = lazy.Value;

	// Show the IsValueCreated is true.
	Console.WriteLine("IsValueCreated = {0}", lazy.IsValueCreated);

	// The object can be used.
	Console.WriteLine("Length = {0}", test.Length);
    }
}

Output

IsValueCreated = False
Test()
IsValueCreated = True
Length = 10


Internals. The most interesting part of types in .NET is their internal implementations. This is an efficient way to learn about making types. For Lazy, the Value property has some elaborate logic that constructs the lazy object.

The Lazy type accounts for boxed value types in many places. The methods LazyInitValue and then CreateValue typically lead to a call to Activator.CreateInstance, which essentially is a convoluted way to invoke the target constructor.


Performance. There is substantial code complexity internal to the Lazy type and this will result in overhead and a performance penalty. Therefore, it is advisable that you only use Lazy on slower, hefty objects.

For example, if an object must read a file, then Lazy will help performance because file IO is slow. Memory operations, though, would not benefit from Lazy initialization to the same extent.

Memory Hierarchy: Performance Optimization

Constructors. In an overloaded constructor, you can specify thread safety, and even specify a Func type that serves as a factory design pattern method. The Func will be invoked when the Value property is referenced.

Func

Concept. Lazy evaluation is an established concept. Languages such as Lisp use lazy initialization. This is described in depth in the chapter on metalinguistic abstraction in the Structure and Interpretation of Computer Programs.

Thunks: The delayed objects are called thunks, and the term forcing refers to the creation of the lazy object (page 401).


Summary. Lazy programmers should consider the Lazy type. This type presents a reliable lazy initialization capability. It can reduce startup times in your C# programs in cases where its overhead is dwarfed by the cost of the initialization.