Lazy Initialization in C#

in programming •  7 years ago 

Lazy Initialization in C#

Or: How to check for null everywhere and nowhere.

The Problem

Do you run into this code a lot?

if (Locations == null) Locations = new List<Vector2>();
// Followed by a bunch of code that uses Locations.

I used to.

I would use the same field in six different places and have to check and ensure it wasn't null in each place.

My Solution

Here's something I like to do:

List<Vector2> _locs;
List<Vector2> Locations
{
   get { return _locs ?? (_locs = new List<Vector2>()); }
}

What's going on here?

The first two lines are clear enough. _locs is the backing field to Locations, which in turn is a property.

The getter for that property uses a feature of C# that is less well-known: the null coalescing operator. (That's the ?? in the getter).

Basically, the NCO says "return the thing on the left unless it's null, in which case, return the thing on the right."

Since assignment in C# returns the result of the assignment, all you have to do to treat an assignment like a value is wrap it in parenthesis.

So we return one of two values: the backing field or, if the backing field is null, the result of initializing the backing field.

This is a form of lazy initialization. Locations doesn't exist until we use it, at which point it magically pops into existence.

More to the point, we move the null test into the property itself. It doesn't pop up in six different methods; it's in one place.

So is this a good thing?

In terms of performance, no. You want to initialize your list once before you use it, and access it directly. A property is a function in disguise and takes three or four times as long to access than a field. That said, if you are writing a game and find that accessing Location is causing a performance drop, it's easy to rewire it behind the scenes. Just replace the property with a field of the same name and make sure it's initialized in the constructor.

I go with this simply because, as a one-man team, I shouldn't be writing games that require a level of performance where this will be an issue.

In terms of Object Oriented doctrine, this may or may not be Evil. I've seen debate on the topic. Neither side provided anything I would consider an argument in the debates I've seen, which leads me to believe it's fairly innocuous. That said, I am not a proponent of OOP, so it's probably a horrible technique that will get you fired and/or bring down your entire code base, and I just don't know it. Use at your own risk.

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

Great to see a C# post on steem!
I think this way is a good way to do it, I'm using similar code since C# 6 was out :)

About performance, depending on your class and how it's used, this might even improve performance because less garbage collection is needed.
e.g. If you initialize a list in a constructor, but only 50% of those classes will ever use it. then those empty lists will require collection later on without providing a benefit.

Also if performance is a huge point, code like this might still be useful in combination with ObjectPool, Span/Memory or an self-upgrading structure like the StringValues class (one shared empty instance, when upgrades into a single, then into a multi value object) instead of calling "new List<>".

However, it always depends on the usecase and project :)

I think especially for newer coders or in parts that are exposed to 3rd party code (e.g. a plugin system), this might be a great pattern to reduce unintended null reference exceptions and improve reliability.

Lazy initialization is only required for resource intensive objects. A list is not. Maybe the elements it contains. A list autoscales. It starts with room reserved for little references. If it needs more room it reserves more space.

It is also worth mentioning that your example is not thread safe. It's better to refer to the Lazy<T> Class:
https://msdn.microsoft.com/en-us/library/dd642331.aspx

  ·  7 years ago (edited)

Yes, for 90+% of use-cases I agree with you.

However, for performance oriented cases:
it is still better to not create an empty list and not to use it's auto-scale if possible (e.g. if you know for sure there are never more than X objects in it). The core reason of this is .NET Garbage Collection.
The more instances it has to collect, the longer the GC pauses are. Also the more memory areas it has to move from Gen0 to Gen1 or has to consolidate, the longer it takes.

If performance is really that critical, then it might be better to go with Span from the beginning, a good blog post about it can be found here: http://adamsitnik.com/Span/
Anyway, always do micro benchmarks for segments where you want to optimize performance in that level. And avoid premature optimization, it's often better to have a function up and running with tests, before doing them.

Also 2 things to be aware of with Lazy<T>:

  • Don't use it for short-lived instances, since by default it's using Activator.CreateInstance, which is known for bad performance.
  • if a factory is used and it's initial initialization throws an exception, all following calls throw the same exception without re-executing the initialization

Congratulations @jackdragon! You have completed some achievement on Steemit and have been rewarded with new badge(s) :

You made your First Vote

Click on any badge to view your own Board of Honor on SteemitBoard.
For more information about SteemitBoard, click here

If you no longer want to receive notifications, reply to this comment with the word STOP

By upvoting this notification, you can help all Steemit users. Learn how here!