Pixata Custom Controls
For Lightswitch

Recent Posts

Popular tags (# posts in brackets)

Anonymous types (3) ASP.NET (5) C# (3) C# tricks and tips (2) Computers (6) Design patterns (3) DomainDataSource (3) Dynamic data (4) Entity framework (3) Entity model framework (5) F# (3) LightSwitch (12) Linq (6) Microsoft (2) MVP (2) MVVM (2) Project Euler (2) RIA services (5) Silverlight (2) SQL Server (4) Unit testing (4) Visual Studio (7) WCF (3) WPF (3)

Gratuitous link to StackExchange

Archives


Categories


Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Actually, as I'm self-employed, I guess that means that any views I expressed here aren't my own. That's confusing!


Acknowledgments

Theme modified from one by Tom Watts
C#/F# code styling by Manoli (for posts pre-2016) and Google code prettify (for post from Jan 2016 and beyond)


My rambling thoughts on exploring the .NET framework and related technologies

# Tuesday, 16 February 2016

I came across a situation recently in which we needed an object in the client. Due to the cost of creating this object, we didn't want to create it when loading up the window as it might not be needed (if the user didn't click the appropriate button), we didn't want to store it on the window's main object graph, but equally, we wanted to keep hold of it once it had been created.

This situation is not uncommon, where you have to create a class that is expensive (in database or bandwidth terms) to create.

The obvious solution to this was to have a private variable for the instance of Expensive, and a second private bool variable to indicate if the Expensive object had been created. We could check the bool before accessing the Expensive variable. Even better, we could create a property that wrapped this up. Imagine our class is wittily named Expensive...

public class Expensive {
  // For our purposes, this will just be a simple class that writes a message to the output
  // window when it is created (so we can see when that happens)
  public Expensive() {
    Debug.WriteLine("Created new instance of Expensive, hash code is " + GetHashCode());
  }
  // Add a property, so we can reference something
  public int AnInteger { get; set; }
}

Note that in many cases you can't simply rely on checking if _expensive is not null, as null may well be a valid value (or lack thereof) for the object. Therefore, you need two variables.

This works, but has a few drawbacks. Firstly, it's a lot of code for a simple requirement. Imagine you needed to do this for several types, you would end up with a lot of boilerplate code. Secondly, this method involves multiple variables for each expensive object you want. Finally, and most importantly, another developer coming along at some future date might not realise how it's supposed to work, and assume that _expensive will always be available, bypassing the bool and causing a null reference exception. Even worse, when they discover the null reference, they might add extra code to create the object, ignoring the code you previously added to do just the same thing. This is not good.

A more elegant solution

Drum roll please... enter Lazy<T>. This neat little class (introduced in .NET 4.0) allows you to wrap all this up in one variable, and not have to worry about the details.

To illustrate, let's define our Expensive class as follows...

public class Expensive {
  // For our purposes, this will just be a simple class that writes a message to the output
  // window when it is created (so we can see when that happens)
  public Expensive() {
    Debug.WriteLine("Created new instance of Expensive, hash code is " + GetHashCode());
  }
  // Add a property, so we can reference something
  public int AnInteger { get; set; }
}

Instead of having the two private variables mentioned before, you just have one of type Lazy. When declaring it, you add the code that creates the instance as a constructor parameter. As a simple example, you could have something like this...

Lazy<Expensive> exLazy = new Lazy<Expensive>(() => new Expensive());

That's about as simple as it gets, but there's no reason why it couldn't include more code that uses (say) a WCF service, database, EF model or whatever in there.

Now, the clever thing is that the class doesn't get created until you actually want it. For example, see the following (rather over-the-top) code...

Debug.WriteLine("About to declare, but not use our lazy value");
Lazy exLazy = new Lazy(() => new Expensive());
Debug.WriteLine("Created the lazy value, but not used yet");
for (int i = 0; i < 5; i++) {
  Debug.WriteLine("  i: " + i);
  if (i > 1) {
    Debug.WriteLine("  Setting exLazy.Value.AnInteger to " + i);
    exLazy.Value.AnInteger = i;
  }
}
Debug.WriteLine("Ended loop, exLazy.Value.AnInteger is " + exLazy.Value.AnInteger);

Debug.WriteLine("Ended loop, exLazy.Value.AnInteger is " + exLazy.Value.AnInteger);

This uses a liberal amount of writing to the Output window so we can see what's happening. When you run it, you see the following...

About to declare, but not use our lazy value
Created the lazy value, but not used yet
  i: 0
  i: 1
  i: 2
  i: 3
  Setting exLazy.Value.AnInteger to 3
Created new instance of Expensive, hash code is 1707556
  i: 4
  Setting exLazy.Value.AnInteger to 4
  i: 5
  Setting exLazy.Value.AnInteger to 5
  i: 6
  Setting exLazy.Value.AnInteger to 6
  i: 7
  Setting exLazy.Value.AnInteger to 7
  i: 8
  Setting exLazy.Value.AnInteger to 8
  i: 9
  Setting exLazy.Value.AnInteger to 9
Ended loop, exLazy.Value.AnInteger is 9

As you can see, the Expensive class isn't actually created until you want it, and from then on, it exists without needing to check it, or create it again. This means that your code can just refer to exLazy.Value all the way through, and rely on the fact that if it doesn't exists, it will be created for you.

The Lazy<T> class also has also a bool property IsValueCreated, which (oddly enough) allows you to check if the value has been created. Not sure quite how useful that is, but it's there if you need it.

Not the sort of thing you need to use every day, but when you do, it provides a more elegant and low-risk approach than the first method.

C#
Comments are closed.