5

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 });
  }
}
Prashant Cholachagudda
  • 13,012
  • 23
  • 97
  • 162
  • Please see [How to make List's Add method protected, while exposing List with get property?](http://stackoverflow.com/questions/3260665/how-to-make-lists-add-method-protected-while-exposing-list-with-get-property?rq=1) for some more detailed answers. – Strategy Thinker Feb 27 '15 at 03:04

7 Answers7

12

Expose Children as ReadOnlyCollection:

public IList<Person> Children  
{  
    get 
    { 
       return new ReadOnlyCollection<Person>(_children);
    }  
} 
Pawel Lesnikowski
  • 6,264
  • 4
  • 38
  • 42
8

Expose Children as IEnumerable<T>

Matthew Scharley
  • 127,823
  • 52
  • 194
  • 222
Alex Reitbort
  • 13,504
  • 1
  • 40
  • 61
8

Change your Children property to this:

public IList<Person> Children 
{ 
  get
  {
     return _children.AsReadOnly();
  } 
}
Thomas Weller
  • 11,631
  • 3
  • 26
  • 34
  • 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` itself readonly, not the items in the list. – Matthew Scharley Oct 08 '09 at 01:18
7

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
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Derive Children class from Collection, and override AddItem() Function to attach father to the item is better option – Benny Oct 07 '09 at 12:10
3

Expose the Children property as ReadOnlyCollection<Person>

public ReadOnlyCollection<Person> Children
{
     get {return _children.AsReadOnly();}
}
devnull
  • 2,790
  • 22
  • 25
3

If you are using .NET 4.5 or greater, you can return _children as IReadOnlyList<T>:

public IReadOnlyList<Person> Children
{
    get
    {
        return _children;
    }
}

How is this different from returning an IList<Person> via _children.AsReadOnly()? IReadOnlyList<Person> doesn't even have the mutation methods. Consider the following code:

somePerson.Children[0] = null;

When using IReadOnlyList<Person> this code will fail to compile. When using .AsReadOnly() this code will result in a runtime exception.

How is this different from returning an ReadOnlyCollection<Person> via _children.AsReadOnly()? There's no ReadOnlyCollection<Person> wrapper object created. Aside from that, I'm not seeing a huge difference.

chwarr
  • 6,777
  • 1
  • 30
  • 57
2

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
  • 19,513
  • 7
  • 48
  • 71
  • 1
    @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 and mutate the "private" List at will. I've updated the example code appropriately. – Wedge Oct 07 '09 at 12:24