Steve Brouillard
Steve Brouillard

Reputation: 3266

Handling C# Properties that shouldn't be null

When setting up some reference type properties for a project I'm working on, I came accross a few properties that needed to be properly initialized to be used and should never be null. I've seen a few ways to handle this and can't really determine if there are any major drawbacks to any of the primary ways I've seen to handle this. I'd like to get the community's opinion about the best way to handle this and what the potential drawbacks to each method might be.

Given a simple class, I've seen several ways to handle making sure a property never has a null version of this class in a property

public class MyClass
{
  //Some collection of code
}

Option 1 - Initialize the backing store

public class OtherClass1
    {
        private MyClass _mC = new MyClass();
        public MyClass MC
        {
            get { return _mC; }
            set { _mC = value; }
        }
    }

Option 2 - Initialize the property in the constructor

public class OtherClass2
    {
        public MyClass MC { get; set; }     

        public OtherClass2()
        {
            MC = new MyClass(); 
        }
    }

Option 3 - Handle initialization as needed in the Getter

public class OtherClass3
    {
        private MyClass _mC;
        public MyClass MC
        {
            get
            {
                if (_mC == null)
                    _mC = new MyClass();
                return _mC; 
            }
            set { _mC = value; }
        }
    }

I'm sure there are other ways, but these are the ones that come to mind and I have seen. I'm mostly trying to determine if there's a well established best practice on this or if there's a specific concern with any of the above.

Cheers,

Steve

Upvotes: 9

Views: 6140

Answers (8)

percebus
percebus

Reputation: 847

Option 1 is the vanilla way. Since back in the old days we didn't had Auto-Implemented Properties (With the { get; set;} sintax) so that was they way to specify the default behaviour.

When Auto-Implemented is introduced, since you are not using directly the field that stores the default value (_mC), a fairly good question rises: "Where do I Initialize it?"

  • Option 2 Is called eager loading: as soon as the class is created.
  • Option 3 Is called lazy loading : only as soon as need it.

I've seen that the commonly accepted way is the Option 2: eager loading, but I believe this is just to minimize code, which is completely acceptable. Problem comes when you start having multiple constructors with multiple signatures and you end up pointing all of them to a void Initialize() method of some sort.

I particularly prefer Option 3, as it is both more declarative per field/property and it is memory optimized.

Take a look at EntityFramework with the different flavors: Code-First or Database-first and you will notice how for built-in properties it uses eager loaders whereas for navigation properties it favors (by default, can be customized) lazy loaders.

Also, take in account what is going on in this loaders. In Entity Framework it means that every time you initialize it makes a trip to the Database and queries a portion of it. You might get nagged reall quick by your DBA of having multiple simultaneous sessions and might want to centralize some transactions in single payloads, hence some re-wiring to do eager loaders might come into play... although you will end up querying huge amounts of data and slow down your UX.

In Code-First you can see the following example:

public class Blog
{ 
    public int BlogId { get; set; } 
    public string Name { get; set; } 
    public string Url { get; set; } 
    public string Tags { get; set; } 

    public virtual ICollection<Post> Posts { get; set; } 
}

In the above, Posts collection is declared as virtual, as it will be modified at runtime depending on your settings. If you set it up for eager loading, it will do it as Option 2, whereas if you set it to lazy, it will be modified similar to Option 3

Hope that was helpful

Upvotes: 0

Mark Brittingham
Mark Brittingham

Reputation: 28865

As far as I know, there is not an established best practice here for a simple reason: each of your options has a different performance/memory footprint profile. The first option is appropriate for a reference to an object that you know must be instantiated in a class that you are sure will be used. Honestly, though, I never take this approach because I think that #2 is just more appropriate; just a sense that this is what a constructor is for.

The last option is appropriate when you are not sure whether an option will be used. It permits you take up the resource only as needed.

BTW, this question is right "next door" to a number of other issues such as the appropriate use of the Singleton pattern, the use of abstract classes or interfaces for your deferred object, etc. that might be useful for you to explore to gain greater insight.

Update: It strikes me that there is at least one case where initializing an instance in the class definition is appropriate (your Option #1). If the instance will be static then this is the only appropriate place to initialize it:

private static readonly DateTime firstClassDate = DateTime.Parse("1/1/2009 09:00:00 AM");

I thought of this when creating the above line of code in some Unit tests I was writing today (the readonly being optional wrt my point but appropriate in my case).

Upvotes: 2

AnthonyWJones
AnthonyWJones

Reputation: 189457

First off should the property never be null or never null on initialisation? I suspect you meant the former in which case your setter code needs to prevent nulls being set.

The basic pattern here is that the outer class state is invalid if the inner class field has not got a valid assignment. In that case not only should the setter defend the field from null but the constructor should ensure its initialised to the correct value.

Your code implies that the outer class can instance the inner class without further input from the consuming code. In the real world the outer class needs further info from the outside in order to either receive an existing instance of the inner class or enough info for it to retrieve one.

Upvotes: 0

Cheeso
Cheeso

Reputation: 192467

options 1 & 2 are syntactically different but essentially equivalent. Option 3 is a lazy init approach that I use very consistently.
I think they all have their uses, and it depends on what you need.

Upvotes: 0

Rowland Shaw
Rowland Shaw

Reputation: 38130

Option (3) has the benefit of not allocating the object until it's needed, it can be easily adapted to be a delay loaded object (so when loading an object from a database -- keep a hold of foreign keys to load the full child object when required)

Upvotes: 0

Shea
Shea

Reputation:

Assuming there's no side effects with regards to when _mC is instantiated, (i.e., all else being equal), I prefer option 3 as that saves the overhead of an additional instance of MyClass on the heap in the case where the getter of MC Is never called.

Upvotes: 0

Renaud Bompuis
Renaud Bompuis

Reputation: 16786

Paraphrasing a question I posted a few days ago but I think it may be helpful to enforce code rules and make sure that Nulls a re not used where you don't want them:

Microsoft just released Code Contracts, a tool that integrates with Visual Studio and allows you to define contracts for your .Net code and get runtime and compile time checking.

Watch the video on Channel 9 that shows how it being used.

For now it's an add-on but it will be part of the Base Class Library in .Net 4.0

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1500505

Best option unless you really can get away with just creating a new instance yourself: only provide constructors which take all the required values, and validate them at that point.

Upvotes: 7

Related Questions