20

There are several options when one class must have a container (collection) of some sort of objects and I was wondering what implementation I shall prefer.

Here follow the options I found:

public class AClass : IEnumerable<string>{
   private List<string> values = new List<string>()

   IEnumerator IEnumerable.GetEnumerator()
   {
      return GetEnumerator();
   }

   public IEnumerator<T> GetEnumerator(){
      return values.GetEnumerator();
   }
}

Pros: AClass is not dependent on a concrete implementation of a collection (in this case List).

Cons: AClass doesn't have interface for Adding and removing elements

public class AClass : ICollection<string>{
   private List<string> values = new List<string>()

   IEnumerator IEnumerable.GetEnumerator()
   {
      return GetEnumerator();
   }

   public IEnumerator<T> GetEnumerator(){
      return values.GetEnumerator();
   }

   //other ICollectionMembers
}

Pros: Same as IEnumerable plus it have interface for adding and removing elements

Cons: The ICollection interface define other methods that one rarely uses and it get's boring to implement those just for the sake of the interface. Also IEnumerable LINQ extensions takes care of some of those.

public class AClass : List<string>{

}

Pros: No need of implementing any method. Caller may call any method implemented by List

Cons: AClass is dependent on collection List and if it changes some of the caller code may need to be changed. Also AClass can't inherit any other class.

The question is: Which one shall I prefer to state that my class contains a collection supporting both Add and Remove operations? Or other suggestions...

Bruno Costa
  • 324
  • 1
  • 5
  • 23

4 Answers4

8

My suggestion is just define a generic List inside of your class and write additional Add and Remove methods like this and implement IEnumerable:

public class MyClass : IEnumerable
{
    private List<string> myList;

    public MyClass()
    {
        myList = new List<string>();
    }

    public void Add(string item)
    {
        if (item != null) myList.Add(item);
    }

    public void Remove(string item)
    {
        if (myList.IndexOf(item) > 0) myList.Remove(item);
    }

    public IEnumerable<string> MyList { get { return myList; } }

    public IEnumerator GetEnumerator()
    {
        return myList.GetEnumerator();
    }
}

This is the best way if you don't want to implement your own collection.You don't need to implement an interface to Add and Remove methods.The additional methods like this fits your needs I guess.

Selman Genç
  • 100,147
  • 13
  • 119
  • 184
  • There is no need for method Add and Remove since you already have a Property to get the list. I like the ideia but I would make it return ICollection instead so it wouldn't have the same cons as my 3rd option. – Bruno Costa Jan 20 '14 at 23:30
  • you right,you can change it to ICollection, or IEnumerable is better.User can't add items to the list directly if you return IEnumerable. – Selman Genç Jan 20 '14 at 23:36
3

Well this is really an opinion based question which aren't specifically what SO is used for. However all implementations have different pro's and con's as you have listed, really the one you implement is the option that best fits the application use.

In my personal opinion I would go with option one and add the methods you need to interface with your inner collection. This is quite simple to implement and simple to use.

Something like.

public class AClass : IEnumerable<string>
{
    public AClass()
    {
        this.values = new List<string>();
    }

    private readonly List<string> values;

    public void Add(string inputString)
    {
        this.values.Add(inputString);
    }

    public void Remove(string inputString)
    {
        this.values.Remove(inputString);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public IEnumerator<string> GetEnumerator()
    {
        return values.GetEnumerator();
    }
}

Now this has simple add \ remove features. Also note I used a readonly list as your list doesnt need to be rest after the constructor has been called.

Update AS Per comment.

Yes you do have convert from a List to the AClass other class (you would have to anyway). I have added an extra constructor and an implicit operator to cast from a List or an IEnumerable in the constructor.

public class AClass : IEnumerable<string>
{
    public static implicit operator AClass(List<string> collection)
    {
        return new AClass(collection);
    }

    public static implicit operator List<string>(AClass aClass)
    {
        return aClass.values;
    }

    public AClass()
    {
        this.values = new List<string>();
    }

    public AClass(IEnumerable<string> collection)
    {
        this.values = collection.ToList();
    }

    private readonly List<string> values;

    public void Add(string inputString)
    {
        this.values.Add(inputString);
    }

    public void Remove(string inputString)
    {
        this.values.Remove(inputString);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public IEnumerator<string> GetEnumerator()
    {
        return values.GetEnumerator();
    }
}

This could then be used as the following ways.:

List<string> listA = new List<string>();

AClass classA = new AClass(); //parameterless constructor
AClass classA1 = new AClass(listA); //simple constructor call with collection
AClass classA2 = (AClass)listA; //direct cast
List<string> listB = (List<string>)listA; //cast back to a list

Just an idea, again still a personal opinion.

Nico
  • 12,493
  • 5
  • 42
  • 62
1

I liked the way you explained your thoughts.

You have found 3 perfectly goods ways of addressing some issues. You pros and cons make me feel you understand them correctly.

There is no silver bullet to tackle all problems. But you better have a software architect toolbox packed with design patterns and a sprinkle of common sense.

Next time you face a challenge use the best tool for the job!

Luis Filipe
  • 8,488
  • 7
  • 48
  • 76
  • And having a doubt like this almost after completing a college degree in computer engineering is quite bad I guess. But hey, all questions shall be made, I was also looking for consistency because whenever this problem occurred I think I faced it in different ways. Now I can have consistency and a way I like and feel reasonable to implement it. – Bruno Costa Jan 21 '14 at 01:36
  • It's not bat at all, quite the opposite. I usually use the generic List or inherit from it when i want to fill some known data in its constructor. But it's not always like this. – Luis Filipe Jan 21 '14 at 10:06
0

This is just a small adaptation of what Selman suggested so his answer meets my expectations:

public class MyClass : IEnumerable<string>
{
   private List<string> myList;

   public MyClass()
   {
       myList = new List<string>();
   }

   public ICollection<string> MyList { get { return myList; } }

   IEnumerator IEnumerable.GetEnumerator()
   {
      return GetEnumerator();
   }

   public IEnumerator<T> GetEnumerator(){
      return myList.GetEnumerator();
   }
}
Bruno Costa
  • 324
  • 1
  • 5
  • 23