I’m heavily geared towards C++ thinking and need some guidance on a specific C# matter. Let’s assume we have the following class:
public class Foo { private IList<Bar> _bars = new List<Bar>(); // Note IList<> vs List<>. public IList<Bar> Bars { get { return _bars; } set { ... } } }
Now, in place of the ..., I’m leaning towards clearing _bars and AddRange the items from the set argument value, instead of just assigning value to _bars. The way I see it, is that I want to keep referencing the same items that the value items references, not the actual IList<Bar> that value references.
Is that wrong thinking on my side? How do you think here?
Edit: After some comments, I realized I must add that I want to be able to use an existing collection of Bars in the Foo ctor and initialize _bars from that collection. So, with that revision and the comments so far, this feels better:
public class Foo { private readonly List<Bar> _bars = new List<Bar>(); public Foo(IEnumerable<Bar> bars) { _bars.AddRange(bars); } public IList<Bar> Bars { get { return _bars; } } }
Is it better?
Absolutely, there is no need to expose a setter for the Bars property. Internally you hold a reference to the collection, which as Kent suggests could be marked as Readonly. Through the getter the caller can do what they want with the collection with the methods available (Add, Remove, Clear, AddRange, etc), but crucially they can never change the internal reference you hold to the collection object.
This then allows you to control what methods are allowed. As Jamie suggests, having the property return type
IEnumerablewould result in the Bars property exposing a readonly collection. ExposingIListmeans the contents of the collection could be modified. A setter on the property would leave it wide open for the caller to do what they want and you are no longer in control.Edit
Following the question edit above. It really depends on how the
Fooobject will be used.Since your main concern is to initialise
Foofrom an existing list ofBarobjects…Your latest code example for
Fooforces the caller to initialise via the constructor but then also allows them to change the collection via the propertyWhen allowing an object to be initialised via the constructor you need to ask yourself why you are doing this. Is it…
You need to ask yourself – Do you want the caller to be able to change the contents of the Bars collection after the
Fooobject has been constructed?If No – Make the Bars property expose a read only collection.
If Yes – Add a default constructor to the
Fooobject so that the caller doesn’t have to supply a list to initialise it. But they will have the option to do so if they so choose via the overloaded constructor.