Lazy<T> uses a level of indirection by wrapping the underlying object. This can cause computational as well as memory issues. To avoid wrapping objects, we can use the static variant of Lazy<T> class, which is the LazyInitializer class.
We can use LazyInitializer.EnsureInitialized to initialize a data member that is passed via a reference as well as an initialization function, like we did with Lazy<T>.
The method can be called via multiple threads, but once a value is initialized, it will be used as a result for all of the threads. For the sake of demonstration, I have added a line to the console inside the initialization logic. Though the loop runs 10 times, the initialization will happen only once for single-thread execution:
static Data _data;
public static void Main()
{
for (int i = 0; i < 10; i++)
...