views:

106

answers:

5

I am wondering what is the best way to use properties when dealing with collections.

For example I have a class Foo and I want to have a list of that class stored. Which of the following should be used:

private List<Foo> myList;
private List<Foo> myOtherList = new List<Foo>();

now for the property:

public List<Foo> ListOfFoo
  {
     get 
     { 
        return myList; 
     }
     set 
     { 
        myList= new List<Foo>(value); 
     }
  }

Or should the set just be to the value?

public List<Foo> ListOfFoo
  {
     get 
     { 
        return myList; 
     }
     set 
     { 
        myList= value; 
     }
  }
A: 

It depends.

When the first style is used, you create a copy of the list, which is generally unnecessary. .Net convention is for the setter to assign the reference to the property. This is why I would lean towards the second option.

However, if you are intending for the copy operation to take place, the first option is what you are looking for.

siz
+2  A: 

Generally you don't want to use properties of a rich type like List<T> (normally one would use Collection<T>), and generally properties of a collection type are read-only - the collection itself can be modified with methods like Clear, Add etc., and this is normally sufficient.

For example:

class Foo
{
    Collection<Bar> _bars = new Collection<Bar>();

    public Collection<Bar> Bars { get { return _bars; } }
}

This also leaves you open to validate modifications to the collection by implementing a descendant of Collection<T> and overriding the InsertItem, SetItem etc. methods.

Barry Kelly
Although in the general case you may not want to use List<T>, it is perfectly ok to do so. For example, if you have an internal data object.
siz
siz - +1, still I'd use the smallest possible interface to the outside (e.g. IList<>)
peterchen
peterchen - Collection<T> has a broader, easier to use interface than IList<T>, and Collection<T> can take the IList<T> implementation to wrap as the constructor. IMHO there is no excuse for using IList<T> over Collection<T>.
Barry Kelly
In the case of a public API, yes, I'd use the smallest interface possible. But for a family of data objects that I use to transfer data over a web service, for example, I like the objects to be pretty dump and be able to use the methods in List<T>, especially since I still develop in .net 2.0/3.0 and don't have access to the LINQ extension methods.
siz
+2  A: 

Choose

private List<Foo> myOtherList = new List<Foo>();

becuse the other just declares a reference (which is set to null), the sample above declares a reference to a list, creates a list and assignes that new list to the reference.

Choose

public List<Foo> ListOfFoo
  {
     get { return myList; }
     set { myList= new List<Foo>(value); }
  }

When you want myList to NOT refelect any changes that happen to the list after it is assigned to myList e.g.

List<string> myFirstList = new List<string>();
myFirstList.Add("Hello");
myFirstList.Add("World");

List<string> mySecondList = new List<string>(myFirstList); 
// mySecondList now contains Hello & world

myFirstList.Add("Boyo");
// myFrist List now contains Hello, world & Boyo
// mySecondList still contains Hello & world

Choose

public List<Foo> ListOfFoo
  {
     get { return myList; }
     set { myList= value; }
  }

When you want both references to point to the same object e.g.

List<string> myFirstList = new List<string>();
myFirstList.Add("Hello");
myFirstList.Add("World");

List<string> mySecondList = myFirstList; 
// mySecondList now contains Hello & world

myFirstList.Add("Boyo");
// myFrist List now contains Hello, world & Boyo
// mySecondList "also" contains Hello, world & Boyo

The "also" above is in quotes, because actually, there is only one list, and both my first and my second point to the same list.

Binary Worrier
A: 

Generally, expose only an Interface (ICollection, IList or similar), and make it readonly:

private IList<Foo> m_list = new List<Foo>();
public IList<Foo> List {get { return m_list; } }

Advantage: You can modify the implementation, e.g. switch from a List to an Observable List. You might need to make the m_list member of the concrete type rather than the interface, e.g. to use additional funcitonality.

With an settable external list, you run into a few problems. However, there are some cases where this is needed:

  • the data can be created externally, and is potentially large, and changes frequently (e.g. tens of thousands of items)
  • the external list should be shared between different instances
peterchen
A: 

Why not use the IEnumerator-Interface on the class and if you have to use a setter, use a certain method.

This way you are hiding the actual List-Implementation as well.

class FooBar : IEnumerator
{
  private Collection<Foo> col;

  public IEnumarator GetEnumerator()
  {
    return col.GetEnumerator();
  }

  public void SetList(Collection col)
  {
    this.col= col; // you can also make this more general and convert the parameter so it fits your listimpl.
  }
}

class Clazz
{
  private void WhatEver(){
    FooBar foobar = new FooBar();
    ...
    foreach(Foo f in foobar)
    {...}
  }
}
lostiniceland