Because of this constraint, I have to instantiate an object a first [emphasis mine]with object initializer and then populate its Books property via AddRange
But the client can set Books to null which is what I don't want.
These alarm bells are all answered by using a constructor. The constructor's purpose is creating valid objects. The constructor guarantees a valid object because it forces the user to provide the arguments required and then applies its internal state rules. Without a constructor the onus is on the user, and every user every time, to enforce that class' rules - and do it correctly.
It should strike the reader as ironic and incongruous that an object was instantiated in order to ensure partial state and then allowing external code to screw it up at will.
Edit
Re: the "am forced to" comment
You're focused on fixing only half the problem. For example, is it really ok for Name to be null or empty string? What's an Author without a name? Calling a method on a null Name string throws an exception. Either deal with everything it in the constructor or you'll be writing error trapping all over the place, including the client code. Client code should not be fixing Authors shortcomings.
But, if you must you can do this. And this "lazy initialization" does not eliminate the need for a decent constructor.
public List<string> Books { get{ return value; } set { if (Books == null) { Books = new List<string>(); } else { Books = value; } } }
But that's buggy. An existing list can be wiped out.
public Author (string name, List<string> books = null) { if(String.isNullOrWhiteSpace(name)) throw new ArgumentException("name is missing"); // P.S. no public setter properties to undo construction Name = name; Books = books; } // suggestion: rewrite to use params keyword to add 1 - many at once public void AddBook( title) { if (String.isNullORWhitespace(title)) return; Books.Add(title); // allows duplicates, fyi.
If anyone feels the urge to up vote, up-vote @HugoJose answer instead. He effectively illustrated this earlier. I'm just trying to explain the goodness of a robust constructor.
end Edit