4

When defining classes I expose class members as properties along the lines of :

class ClassA
{
    private String _Name;

    public String Name
    {
        get { return _Name; }
        set { _Name = value; }
    }
 }

What is best practice for dealing with collections within classes, with respect to accessors

So if the class is extended to something like :

class ClassA
{
    private String _Name;
    private List<String> _Parts = new List<String>();

    public String Name
    {
        get { return _Name; }
        set { _Name = value; }
    }
 }

How do I expose the next item?

BENBUN Coder
  • 4,801
  • 7
  • 52
  • 89

8 Answers8

4

Expose a read-only instance of the collection. Note that the contents are not read-only, but the reference is.

public IList<String> Parts { get; private set; }
Phil Hunt
  • 8,404
  • 1
  • 30
  • 25
  • 3
    public IList would be better. http://stackoverflow.com/questions/1232108/c-difference-between-listt-and-collectiont-ca1002-do-not-expose-generic-l – Iain Galloway Dec 23 '10 at 16:30
  • Aye. If I was being picky I'd say use an IEnumerable unless you've got a really good reason not to. – Iain Galloway Jan 03 '11 at 10:00
2

The naming conventions I've come across recommend

private String _name;

Also you could use automatic properties which generate the same code you've written

public string Name {get; set;}

For collections, I don't like to expose the actual collection but methods to work on it.

public void Add(...
public void Remove(...

Otherwise you could make it readonly with an automatic property

public IList<string> Parts {get; private set;}
Yuriy Faktorovich
  • 67,283
  • 14
  • 105
  • 142
  • 2
    It depends on whether your object *is* a collection, or *has* a collection. E.g. a winforms Control is not a collection of its Children, but a DataGridViewRowCollection certainly is. – Iain Galloway Dec 23 '10 at 16:38
1

It depends on how serious you are about encapsulating the way the data is stored. If you're doing a lightweight class and you are just providing the storage but want to leave the accessing decisions completely up to the consumer of your class, you just expose it like a standard property or make it an auto-property.

public List<String> Parts { get; private set; }

If you want to ensure the variable is never null, continue to use your private backing field and add checks.

private List<String> _Parts;
public IList<String> Parts
{
    get
    {
        if (_Parts == null)
            _Parts = new List<String>();
        return _Parts;
    }
    private set
    {
        if (value != null)
            _Parts = value;
    }
}

If, however, you want to control synchronization, or anything else of that sort, you'd expose methods that are logical for what you're doing.

public void AddPart(String part);
public void RemovePart(String part);
public String GetPart(int index);
public IEnumerable<String> GetAllParts()
{
    foreach(String part in _Parts)
        yield return part;
}
Erik Noren
  • 4,279
  • 1
  • 23
  • 29
1

I don't know if there is specifically a best practice in place, but there are a couple things to consider. The basic approach is the same as what others have stated:

public List<String> Parts
{
    get { return _Parts; }
    private set { _Parts = value; }
}

The important point here is to make sure that _Parts is never null. That leads to subtle and hard to discover bugs.

However, if you need to send events when elements are added and removed you have only two options:

  • Use a subclass of List that sends the events when appropriate
  • Don't expose the List at all, and merely expose the AddPart(), RemovePart(), and ListParts() (that returns a copy of the current list).

If your needs are simple, just expose the property (but protect it from being assigned null). Otherwise you'll have to be a bit more fancy.

Berin Loritsch
  • 11,400
  • 4
  • 30
  • 57
0

Couldn't you just do the same - but for the list?

public List<String> parts
    {
        get { return _Parts; }
        set { _Parts = value; }
    }
m.edmondson
  • 30,382
  • 27
  • 123
  • 206
0

I would expose as property as well

public List<string> Parts { get; set; }
Vlad Bezden
  • 83,883
  • 25
  • 248
  • 179
0

You have a bunch of options and it really depends on what kind of operations you want to open up to the public API of your class. The most common approaches are:

  • Provide a readonly property to returns the actual collection instance with the same type information.
  • Provide a readonly property that returns an IEnumerable interface.
  • Provide a readonly property that returns a ReadOnlyCollection wrapper of the collection.

Again, it really depends on how you want to expose the collection, but the 3 options above will work fine in most scenarios. If you have more specialized requirements like allowing additions to the collection from the public API while at the same time disallowing removals then things get a bit more complicated.

Brian Gideon
  • 47,849
  • 13
  • 107
  • 150
0

We typically do the following:

private Collection<String> _parts = new Collection<String>();
public Collection<String> Parts {
  get { return _parts; }
}

This ensures that the collection is instantiated when the object is created and it makes the underlying reference for the _parts collection read only. Which means you can add/remove parts but you can't change what the property points to.

NotMe
  • 87,343
  • 27
  • 171
  • 245