views:

204

answers:

6

I have Class called Person containing to properties, Father and List of Children.

I want every one to use only AddChild Method to add children, not the List.Add method , so how do I restrict use of it?

public class Person
{
  private List<Person> _children = new List<Person>();
  public string Name { get; set; }
  public Person Father { get; set; }
  public List<Person> Children 
  { 
    get
    {
       return _children;
    } 
  }
  public void AddChild(string name)
  {
      _children.Add( new Person { Name = name, Father = this });
  }
}
+12  A: 

Expose Children as ReadOnlyCollection:

public IList<Person> Children  
{  
    get 
    { 
       return new ReadOnlyCollection<Person>(_children);
    }  
}
Pawel Lesnikowski
+8  A: 

Expose Children as IEnumerable<T>

Alex Reitbort
+7  A: 

If you are exposing the underlying List<T>, then in short: you can't.

You could write your own collection-wrapper class, or perhaps inherit from Collection<T> (which still exposes Add, but you can override a few things to sense-check data before it is added).

Marc Gravell
Derive Children class from Collection<T>, and override AddItem() Function to attach father to the item is better option
Benny
+3  A: 

Expose the Children property as ReadOnlyCollection<Person>

public ReadOnlyCollection<Person> Children
{
     get {return _children.AsReadOnly();}
}
devnull
+6  A: 

Change your Children property to this:

public IList<Person> Children 
{ 
  get
  {
     return _children.AsReadOnly();
  } 
}
Thomas Weller
Will the children of the children be read only?
wcm
No. Only the list itself is read only.
Matthew Scharley
That said, the `Children` of any instance of a `Person` class will be accessed via this getter, so yes, they will be *in this case*. But generally speaking, using `.AsReadOnly()` only makes the `List<T>` itself readonly, not the items in the list.
Matthew Scharley
+2  A: 

An IEnumerable works just fine:

public IEnumerable<Person> Children
{
    get
    {
        return _children.AsReadOnly();
    }
}

or the more long winded:

public IEnumerable<Person> Children
{
    get
    {
        foreach (Person child in _children)
        {
            yield return child;
        }
    }
}
Wedge
A `List<Person>` is already an `IEnumerable<Person>`
Matthew Scharley
@Matthew, thanks for pointing that out. Actually, this reminded me that AsEnumerable() is just a cast of the reference to the List, client code could simply cast back to List<Person> and mutate the "private" List at will. I've updated the example code appropriately.
Wedge