Lazy. Lazy instantiation delays certain tasks. It typically improves the startup time of a C# application. This has always been possible to implement.
A special type. This type enables lazy loading (lazy instantiation) with a simple wrapper class. It can reduce duplicated code that implements the needed logic.
Example. In this program, you will first see the Test class. This class contains a constructor and an allocation occurs in the constructor.
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);
}
}IsValueCreated = False
Test()
IsValueCreated = True
Length = 10
Performance, new Lazy. There is substantial code complexity internal to the Lazy type and this will result in overhead and a performance penalty. So use Lazy on slower, hefty objects.
Version 1 This version of the code creates a NumberAdder instance each time. It accesses a field on the object.
Version 2 This code creates a Lazy instance that contains a NumberAdder. It shows the overhead of Lazy.
Result Creating a Lazy instance causes some performance loss. But if we can reuse the same Lazy instance many times, this is reduced.
using System;
using System.Diagnostics;
using System.IO;
class NumberAdder
{
public int _result;
public NumberAdder()
{
_result = 10 + 2;
}
}
class Program
{
const int _max = 1000000;
static void Main()
{
// Version 1: create an object each time.
var s1 = Stopwatch.StartNew();
for (int i = 0; i < _max; i++)
{
var number = new NumberAdder();
if (number._result != 12)
{
return;
}
}
s1.Stop();
// Version 2: create Lazy, and access Value each time.
var s2 = Stopwatch.StartNew();
for (int i = 0; i < _max; i++)
{
var lazy = new Lazy<NumberAdder>();
if (lazy.Value._result != 12)
{
return;
}
}
s2.Stop();
Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns"));
Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns"));
}
} 5.09 ns new NumberAdder
68.24 ns new Lazy<NumberAdder>, get Value
Performance, value cache. Here is a benchmark that shows the performance benefit of Lazy. We have a class NumberMultiplier that is slow to create.
Version 1 In this version of the code, we create a NumberMultiplier instance each time it is needed.
Version 2 We create the Lazy wrapper around NumberMultiplier, and then reuse the Lazy instance, for a performance gain.
Result We can use Lazy to avoid creating an object until needed, and this can speed up programs.
using System;
using System.Diagnostics;
class NumberMultiplier
{
public int _result;
public NumberMultiplier()
{
var array = new int[1000];
for (int i = 0; i < array.Length; i++)
{
array[i] = i;
array[i] *= i;
_result = array[i];
}
}
}
class Program
{
const int _max = 1000000;
static void Main()
{
// Version 1: perform computation each time.
var s1 = Stopwatch.StartNew();
for (int i = 0; i < _max; i++)
{
var number = new NumberMultiplier();
if (number._result == 0)
{
return;
}
}
s1.Stop();
// Version 2: use Lazy Value.
var s2 = Stopwatch.StartNew();
var lazy = new Lazy<NumberMultiplier>();
for (int i = 0; i < _max; i++)
{
if (lazy.Value._result == 0)
{
return;
}
}
s2.Stop();
Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns"));
Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns"));
}
}1037.23 ns new NumberMultiplier
1.28 ns Lazy.Value
Lazy, internals. The most interesting part of types in .NET is their internal implementations. This is an efficient way to learn about making types.
And For Lazy, the Value property has logic that constructs the lazy object. The Lazy type accounts for boxed value types in many places.
Info Lazy InitValue and CreateValue typically lead to a call to Activator.CreateInstance, which is a way to invoke the target constructor.
Constructors. In an overloaded constructor, you can specify thread safety, and even specify a Func type that serves as a factory design pattern method.
A summary. Lazy represents a reliable lazy initialization capability. It can reduce startup time in cases where its overhead is dwarfed by the cost of the initialization.
Dot Net Perls is a collection of tested code examples. Pages are continually updated to stay current, with code correctness a top priority.
Sam Allen is passionate about computer languages. In the past, his work has been recommended by Apple and Microsoft and he has studied computers at a selective university in the United States.