I've recently read something about using interfaces when exposing collections instead of concrete implementations (IEnumerable instead of List). I'm trying to do that now in my code. However, when I expose a property that return IEnumerable, I'm having some difficulty of not allowing nulls as a return value. Example:
public class HumanResource
{
public IEnumerable<EmployeeModel> Employees
{
get
{
// return what?
}
}
}
What should I return in the getter? I don't want to use automatic properties for this as I want to avoid nulls. What I want is to return a new collection with no items. Of course I can return any type that implements IEnumerable but how will the external user of the class know that? Or did I understand this exposing interface instead of concrete implementations wrong?
EDIT: Removed setter
Of course I can return any type that implements IEnumerable but how will the external user of the class know that?
They don't have to know that, that's exactly the point.
Your property promises to return an IEnumerable<EmplyeeModel>, and that's exactly what happens. It doesn't matter which class implementing this interface your code returns.
What I want is to return a new collection with no items.
So, Enumerable.Empty<EmplyeeModel>() or new List<EmployeeModel>() will do just fine.
When designing an API you need to think about what the consumers will do with the data types you return, and decide upon that accordingly.
Usually an IEnumerable<T> for collections suits everyone. When they want it in a list, they can do new List<T>(yourEnumerable), or yourEnumerable.ToArray() to use it as an array.
What I want is to return a new collection with no items.
Properties let you do that very easily:
public class HumanResource
{
// This is the real employees that gets returned when its not null
private IEnumerable<EmployeeModel> employees; // may be null
// This is the empty IEnumerable that gets returned when employees is null
private static readonly IEnumerable<EmployeeModel> EmptyEmployees =
new EmployeeModel[0];
public IEnumerable<EmployeeModel> Employees
{
get
{
return employees ?? EmptyEmployees;
}
set {};
}
}
The code returns an empty array when employees variable is set to null. You can set employees to a collection of any type that implements IEnumerable<EmployeeModel>, or even to an array if you prefer. This is possible because you return by interface.
The flip side of this, of course, is that the clients would have no direct access to methods of properties that are not exposed through the interface. For example, if employees is actually a List, the callers would have to use LINQ's Count() instead of obtaining .Count directly. Of course you can expose a different interface, say, IList<EmployeeModel>, to let your clients use additional methods.
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
Related
First of all, I have read the question asking for the difference between fields and properties and I know what it is used for.
Now on to my question, I wanted to create a property where I am sure that get and set will both be empty, so I do get; set;. All good and well. But now I realised that I have just made a public field with a capital name, it is in all ways identical.
Even the argument of it being used so future code does not depend on implementation cannot be said, as I can simply make this a property and implement a getter or a setter. The semantics of a field and a property are identical outside the class it is defined in.
So my question is, should I use a field or a property when a property would simply use get;set;?
So this:
public IEnumerable<string> Products;
is identical in all ways to this:
public IEnumerable<string> Products { get; set; }
should I use a field or a property when a property would simply use get;set;?
Use a property... for the practical reasons below, and for the philosophical reasons that properties expose a state API, whereas fields expose a state implementation detail.
The semantics of a field and a property are identical outside the class it is defined in.
That's not true.
The difference is visible via reflection, which is often very important. For example, many binding frameworks won't use fields, only properties.
You can pass a mutable field by ref, but not a property - so changing a field to a property breaks source compatibility. (Code using SomeMethod(ref x.Products) will become invalid when Products becomes a property.)
Changing a field to a property also breaks binary compatibility, so if assembly X was built against assembly Y v1.0, and you change a field to a property for assembly Y v1.1, then you'd need to rebuild assembly X or it would fail to execute correctly
If you have a mutable value type (please don't do this) then writing foo.Location.X = 10 works when Location is a field (because x.Location is classified as a variable) whereas it doesn't when Location is a property (because then the expression x.Location is classified as a value). If you have a method (in your evil mutable type) which mutates the value instead, then foo.Location.DoSomething() will compile in both cases, but have a different effect. Fun for all the family.
Its depend on the situation. I'll prefer to use the property over the field. You have mentioned that public IEnumerable<string> Products; and public IEnumerable<string> Products { get; set; } are same, but in actual they are not. During compilation the property will get converted into two methods (i.e. get_Products() and set_Products()).
The advantage of property is to allows you to specify the custom code before assigning and returning the data, this is not possible with the field. Check the example below
public IEnumerable<string> Products
{
get
{
if(DateTime.Now.Date > Convert.ToDateTime("01-01-2016"))
{
//Return future product
return new List<string>();
}
else
{
// return current products
return new List<string>() { "testing" };
}
}
set
{
if (DateTime.Now.Date > Convert.ToDateTime("01-01-2016"))
{
//ignore assign product
Products = new List<string>();
}
else
{
// add assign product
Products = value;
}
}
}
Using the auto-property syntax is preferable because it creates a read/write property with a private backing field, thus allowing you to change the implementation (from a private scalar field to a dictionary entry or another backend with some other custom logic), thus freeing the "class's interface" (not the same thing as an interface) from its implementation.
Note that for collection member properties, it is advisable to make their setters private, like so:
public IEnumerable<String> Products { get; private set;}
...that way only the containing class can alter it.
Another alternative is the private readonly field, in C# 6 you can use auto-implemented properties with readonly backing fields like so:
public IEnumerable<String> Products { get; } = SomeSource.GetProducts();
Why I can implement a read-only property like so...
public IList<object> SelectedItems { get; }
...and still be able to use its members, like Add, Remove, etc. when I use the property ?
Isn't readonly supposed to be readonly "all the way down" ?
isn't readonly supposed to be readonly "all the way down" ?
This isn't a "readonly" type. It's a property where you can retrieve the value (the IList<object>), but can't set the value to a different instance of IList<object> as there is no property setter.
No. It's not readonly "all the way down" - the fact that the property only has a getter means you can get the value, but you can do anything you wish with it.
Note that I'd be careful using the term "readonly". C# has a different, distinct meaning and dedicated readonly keyword, which applies only to fields. This isn't "readonly" in the C# meaning, but a property which only provides a get operation.
If you want to have a "read only" list, a good option is to return a ReadOnlyCollection<T>. For example, if your internal class is a List<T>, you can use:
public IList<object> SelectedItems { get { return this.selected.AsReadOnly(); } }
If you are going to do this, it might be better to actually return the ReadOnlyCollection<T> as well:
public ReadOnlyCollection<object> SelectedItems { get { return this.selected.AsReadOnly(); } }
This way, users won't expect that it's safe to call .Add() on the resulting list.
I tried to find a similar question on SO but had no luck. Apologies if it's a duplicate.
What are drawbacks to instantiating class-type variables when they are declared?
In a lot of classes representing Business Object Model we have things like this:
public class RateArea {...}
public class FlatRateSchedule
{
public string ScheduleID {get;set;}
public decimal MaxAmount {get;set;}
}
public class PricingData
{
private List<RateArea> rateAreaList = new List<RateArea>();
private FlatRateSchedule flatRateSchedule = new FlatRateSchedule();
public List<RateArea> RateAreaList
{
get { return rateAreaList; }
set { rateAreaList = value; }
}
public List<FlatRateSchedule> FlatRateScheduleList
{
get { return flatRateScheduleList; }
set { flatRateScheduleList = value; }
}
}
At some point this PricingData class is initialized and some properties are hydrated (but not always all properties).
The thinking being that we're creating "blank" instances of classes so that no properties are ever null. This is convenient because we never have to check if any property is null before accessing it's members. Whether properties are hydrated or not, they would never be "null" to the consuming class. If the properties aren't initialized then code needs to check for null every time before accessing a property.
Is a blanket convention that "all properties of a class should be initialized at all times and never be null" really bad?
Besides using some resources to instantiate and store these "default" class instances, the savings in null-exception-checking code seem to be worth it. Are we missing something?
Not an expert here but
If its a List, it does need to be initialized since you can't add elements if it isn't.
If, throughout the life of your class, your properties may not be always needed you can lazy load them.
You could use .Net 4.0's Lazy<T> class.
From Msdn : "Use an instance of Lazy to defer the creation of a large or resource-intensive object or the execution of a resource-intensive task, particularly when such creation or execution might not occur during the lifetime of the program."
Other than that I think it would be intensive for all your properties to be null and have every consuming class do null checks. Lazy<T> solves this.
I like to initialize values to avoid having to check for null throughout my application. I'd probably go with lazy loading:
public List<RateArea> RateAreaList
{
get {
rateAreaList = rateAreaList ?? new List<RateArea>();
return rateAreaList;
}
set { rateAreaList = value; }
}
As long as your properties are only lists (as in your example), it may be a good convention, making your code more compact and easier to read. Lists can be empty, and if you don't need to distinguish between an empty list and a null reference, this works fine. But if your properties contain other "Business Objects", this may not work so easily. Often the construction of those "child" Business Objects cannot or shall not be done at the time when the "parent" object is constructed.
I'm writing a class to represent a Pivot Collection, the root object recognized by Pivot. A Collection has several attributes, a list of facet categories (each represented by a FacetCategory object) and a list of items (each represented by a PivotItem object). Therefore, an extremely simplified Collection reads:
public class PivotCollection
{
private List<FacetCategory> categories;
private List<PivotItem> items;
// other attributes
}
What I'm unsure of is how to properly grant access to those two lists. Because declaration order of both facet categories and items is visible to the user, I can't use sets, but the class also shouldn't allow duplicate categories or items. Furthermore, I'd like to make the Collection object as easy to use as possible. So my choices are:
Have PivotCollection implement IList<PivotItem> and have accessor methods for FacetCategory: In this case, one would add an item to Collection foo by writing foo.Add(bar). This works, but since a Collection is equally both kinds of list making it only pass as a list for one type (category or item) seems like a subpar solution.
Create nested wrapper classes for List (CategoryList and ItemList). This has the advantage of making a consistent interface but the downside is that these properties would no longer be able to serve as lists (because I need to override the non-virtual Add method I have to implement IList rather than subclass List. Implicit casting wouldn't work because that would return the Add method to its normal behavior.
Also, for reasons I can't figure out, IList is missing an AddRange method...
public class PivotCollection
{
private class CategoryList: IList<FacetCategory>
{
// ...
}
private readonly CategoryList categories = new CategoryList();
private readonly ItemList items = new ItemList();
public CategoryList FacetCategories
{
get { return categories; }
set { categories.Clear(); categories.AddRange(value); }
}
public ItemList Items
{
get { return items; }
set { items.Clear(); items.AddRange(value); }
}
}
Finally, the third option is to combine options one and two, so that PivotCollection implements IList<PivotItem> and has a property FacetCategories.
Question: Which of these three is most appropriate, and why?
The best thing to do here is to create your own collection class that inherits System.Collections.ObjectModel.Collection<T> and overrides InsertItem.
Its typical to expose internal data structures as properties to your business class. But when we have to expose array-like structures (like List<Rule> rules) we might encounter a problem of wrong usage (as in Option 1).
Its suggested to expose clone of such data structures as properties, so that internal structure does not get disturbed.
Does any one have a well-settled solution for this?
public class Rule
{
}
public class RulesManager
{
List<Rule> rules = new List<Rule>();
public List<Rule> Rules
{
get { return rules; }
set { rules = value; }
}
public void Add(Rule r)
{
rules.Add(r);
// Do something else after add;
}
public void Delete(Rule r)
{
rules.Remove(r);
// Do something else after delete;
}
}
public class CallingCode
{
public static void Main()
{
RulesManager r = new RulesManager();
// Option 1
r.Rules.Add(new Rule());
// Option 2
r.Add(new Rule());
}
}
Instead of returning a Clone, you can return a read-only version of rules using rules.AsReadOnly().
public IList<Rule> Rules
{
get { return rules.AsReadOnly(); }
// set { rules = value; -- should not be allowed to set if read only!
}
Note the IList.
Instead of returning a List you can return an IEnumerable. The IEnumerable allows the user to iterate through the collection, but it doesn't allow the user to modify it easily.
Alternatively you could return an arryay instead of a list. This will create a copy of the list that the user cannot easily modify.
Finally you should be aware that the user might also modify the contents of the collection. This may be what you want, but you might also want to return copies of your items.
I think it is quite common to expose the IList as a property, but I prefer to expose only explicit Add/Delete functions. You can also consider to implement one of the collection interfaces in your class (IList for instance), if you are developing something more of a framework.
Instead of:
public List<Rule> Rules
{
get { return rules; }
set { rules = value; }
}
I prefer to implement IEnumerable<T> and an indexer on the class, so that I have control over what happens to the list.
Check out the ReadOnlyCollection and the AsReadOnly() List method.
A basic workaround is to use List<T>.AsReadOnly() method, which will wrap the list around a ReadOnlyCollection to block any "write" access. Of course, you'd have to make the setter private, otherwise it would not make sense...
Another alternative would be to implement your own IList that would alert you in case of "write" access and allow you to perform your business logic.