Reputation: 15101
I want the Books
not to be null
so I made it an initialized readonly property as follows.
class Author
{
public int Id { get; set; }
public string Name { get; set; }
public List<string> Books { get; } = new List<string>();
}
Because of this constraint, I have to instantiate an object a
first with object initializer and then populate its Books
property via AddRange
as follows.
class Project
{
void Main()
{
Author a = new Author
{
Id = 100,
Name = "Bill Gates"
};
a.Books.AddRange(new string[] { "Asp.net", "C++", "C#" });
}
}
Is there any trick to make the instantiation of a
(as well as populating its Books
) simpler just with object initializer?
Upvotes: 0
Views: 1278
Reputation: 5101
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 Author
s 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
Upvotes: 1
Reputation: 369
you can use private set
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
public List<string> Books { get; private set; }
public Author(params string[] books)
{
Books = new List<string>(books);
}
}
or use just get (readonly option)
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
public List<string> Books { get; }
public Author(params string[] books)
{
Books = new List<string>(books);
}
}
The private option I can change the instance of the list any time inside Author, but any other class outside Author just read it.
The read-only option I can't change any time. I initialize it in the constructor after that it will never change.
You can also use readonly collection, no body will add or remove books after the initialization.
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
public ReadOnlyCollection<string> Books { get; }
public Author(params string[] books)
{
Books = new ReadOnlyCollection<string>(books);
}
}
Upvotes: 1
Reputation: 15101
class Author
{
public int Id { get; set; }
public string Name { get; set; }
public List<string> Books { get; } = new List<string>();
public Author(params string[] books)
{
Books.AddRange(books);
}
}
class Project
{
void Main()
{
Author a = new Author("Asp.net", "C++", "C#")
{
Id = 100,
Name = "Bill Gates"
};
}
}
Upvotes: 1