3

I have a class that contains a private List. I have created a getter and a method to add elements to the list:

public class Test{

    private List<T> myList;
    public List<T> MyList
    {
        get { return myList; }
    }

    public Test()
    {
         myList = new List<T>();
    }

    public void AddElements(T element)
    {
         // Do dome stuff, subscribe to an event of T
         myList.Add(element);
    }
}

Since everytime an element is added to my list I want to do more things, I do not want that in some part of the code someone add an element directly:

Test test = new Test();

// Wrong
test.MyList.Add(element);

// Right
test.AddElements(element);

I have thought on creating a new class that implements the IList interface and overrides the Add() method, but I was wondering if there is a more simple/elegant way on "block" this Add() method.

Ignacio
  • 806
  • 1
  • 10
  • 29
  • 1
    Don't expose `List` if you don't want someone being able to modify it. You can expose [`ReadOnlyCollection`](https://msdn.microsoft.com/en-us/library/e78dcd75(v=vs.110).aspx), then no one can add (unless they use reflection). – Sinatr Feb 26 '16 at 12:18

4 Answers4

7

If you are using at least .NET 4.5, return a IReadOnlyList<T>.

public class Test{

    private List<T> myList;
    public IReadOnlyList<T> MyList
    {
        get { return myList; }
    }

    public Test()
    {
         myList = new List<T>();
    }

    public void AddElements(T element)
    {
         // Do dome stuff, subscribe to an event of T
         myList.Add(element);
    }
}
Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
5

I would return as ReadOnlyCollection<T>

Use it like:

public class Test<T> 
{

    private List<T> myList;
    public ReadOnlyCollection<T> MyList
    {
        get { return myList.AsReadOnly(); }
    }

    public Test()
    {
        myList = new List<T>();
    }

    public void AddElements(T element)
    {
        // Do dome stuff, subscribe to an event of T
        myList.Add(element);
    }
}

This way you prevent casting... It will Wrap your List<> with a ReadOnlyCollection class.


Or you could return it as an Array like:

public T[] MyList
{
    get { return myList.ToArray(); }
}

The ToArray() method will create a copy of the list


When it is Returned as an IReadOnlyList<T>. You could simply cast it back..

Test test = new Test<int>();

test.AddElements(10);

((List<int>)test.MyList).Add(20);

foreach(var i in test.MyList)
    Console.WriteLine(i);
Jeroen van Langen
  • 21,446
  • 3
  • 42
  • 57
3

In Test class expose the List as IReadOnlyList<T> then you wont be allowed to use MyList.Add directly

public class Test{

    private List<T> myList;
    public IReadOnlyList<T> MyList
    {
        get { return myList; }
    }

    public Test()
    {
         myList = new List<T>();
    }

    public void AddElements(T element)
    {
         // Do dome stuff, subscribe to an event of T
         myList.Add(element);
    }
}

Edit updated it IEnumerable to IReadOnlyList. There are benifits in using IReadOnlyList - IEnumerable<T> vs IReadOnlyList<T>

Community
  • 1
  • 1
Carbine
  • 7,849
  • 4
  • 30
  • 54
1

If the only reason for your getter is to add elements you won´t need to directly access the list at all, but you can wrap the call to the Add-method into your own method:

class MyClass<T> {
    private List<T> _myList ...

    public void AddElements(T element)
    {
         // Do dome stuff, subscribe to an event of T
         _myList.Add(element);
    }
}

Exposing a generic list is furthermore avoided by CA1002

MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111