You still need to provide an internal backing collection for the property in your class. You can initialize the collection in the constructor, or in the field declaration:
public class HumanResource
{
private readonly IList<EmployeeModel> _employees = new List<EmployeeModel>();
public IEnumerable<EmployeeModel> Employees
{
get
{
return _employees;
}
// No Setter - callers may only enumerate the collection
}
}
As an aside, note that even if you did use an automatic property (e.g. List<EmployeeModel>
), that it would assume a default value of null, unless otherwise initialized elsewhere, so nothing changes in this respect.
Edit, Re : What are the benefits?
- By removing the setter, or making it private, we prevent a caller from reassigning the internal collection of a
HumanResource
- By softening the collection from a
List<>
to an IEnumerable<>
, it means the caller can only do read-only actions on the internal collection, such as to iterate it. In addition, IEnumerable<>
can be used in a lazy iteration, allowing the caller to quit enumerating as soon as it has the data it needs.
- As per the comment below, if the caller requires the data represented in a different collection, such as an
Array
, then LINQ extension methods such as .ToArray()
, .ToList()
, .ToDictionary()
can be used. Doing so will create new collections for the caller, but with references to the same EmployeeModel
objects. The performance penalties of doing this are minimal.
One final note is that there is usually no point in making the setter on an IEnumerable
property private, or declaring the backing field as an IEnumerable
, as this will prevent the class itself from using impure methods to manipulate the collection (i.e. add or remove objects from it), as doing so would require a cast, e.g.:
public class HumanResource
{
public IEnumerable<EmployeeModel> Employees
{
get;
private set;
}
public HumanResource()
{
// Although the property can be assigned in the CTor to prevent the null issue ...
Employees = new List<EmployeeModel>();
}
private void AddProductiveEmployee()
{
// ... We need to continually cast within the class, which is just silly.
(Employees as IList).Add(new EmployeeModel());
}
We would have the same problem with the manual backing field approach with an internal IEnumerable<>
// Unlikely to be useful
private readonly IEnumerable<EmployeeModel> _employees = new List<EmployeeModel>();
TL;DR
- Use a collection type which is appropriate for the internal usage to the class (OO composition)
- But on the external interfaces (e.g. public getter / property), hide the internal implementation to the minimum necessary (OO encapsulation)
- Initializing the internal collection in the constructor (or inline) will prevent a null collection being exposed