-1

What is the best way of initializing objects for properties without setters in C#?

For example I have property of type UserData and I can initialize it:

  1. In constructor
  2. In getter

    private UserData _user;
    
    public UserData User  
    {  
        get  
        {  
            return _user?? (_user= new UserData ());  
        }  
    }
    
  3. Initialize field:

    private UserData _user = new UserData()

I found few similiar threads:
Create an object in the constructor or at top of the class
C# member variable initialization; best practice?

But it is consideration between 1st and 3rd option - no one thinks about 2nd option - do you know way? From some time it is my preffered option to get objects, but I wonder if there are some cons that I don't know.

Could you tell me what is the best option and what problem could make use of 2nd option?

Community
  • 1
  • 1
Marek Kwiendacz
  • 9,524
  • 14
  • 48
  • 72

3 Answers3

3

It all depends on what you want to do with it, so there is definite answer for that.

One difference between 1+3 and 2 is predictability.
With 1+3, you know exactly where your object is created and at which point during instantiation of your class. That can be desirable in some circumstances.
With 2, you depend on external influences (who accesses the property at which time) to initialize the field.

With the delayed creation in approach 2 (only create the object if needed), you could save some time when creating an object of the containing class.

If the UserData's creation takes a lot of time, like, when you have to query a database for it, you might want to delay its creation until really necessary. The object that contains the UserData object is constructed faster since it doesn't need to wait for the UserData object to be created. If the property isn't always accessed, you might even get to completely avoid creating a UserData instance.

Botz3000
  • 39,020
  • 8
  • 103
  • 127
  • Another difference is one of developer maintenance. Option 1 is "by convention" if multiple constructors are created. Option 3 ensures the field is set regardless of the number of constructors. – user7116 Jul 25 '12 at 14:21
0

If you're simply using plain data, initializing the backing field at its definition (if possible) is preferred:

// when you create constructor N+1, no worries about forgetting to set the value
private UserData _userData = new UserData();

public UserData User
{
    get { return _userData; }
}

If you need initialization to be deferred, your best option is using Lazy<T>:

private Lazy<UserData> _userData = new Lazy<UserData>(() => new UserData());

public UserData User
{
    get { return _userData.Value; }
}    

The constructor for Lazy<T> contains overloads which can address your thread safety needs:

  • None: access from multiple threads is "undefined behavior"
  • PublicationOnly: the first thread to complete initialization "wins"
  • ExecutionAndPublication: locks ensure only one thread initializes the value
user7116
  • 63,008
  • 17
  • 141
  • 172
0

One issue with #2 is if the property could be accessed by multiple threads you could potentially create two copies of the UserData object. An additional consideration with #2 is if UserData is expensive to create you will be paying the cost of creating that object when the property is accessed rather than when the containing object is created. That may or may not be desirable depending on your use case.