List<Employee> or EmployeeList?


In current versions of C#, to get a strongly-typed collection, you need to define a separate type for that collection. So if you want to expose a collection of employees, you created an EmployeeCollection class.

With generics, it’s now possible to just use List<Employee>, and it’s also possible to write a pretty simple version of Employee collection as well:

class EmployeeCollection: List<Employee> {}

So, which one is preferred?

My advice is to prefer List<Employee>, as anybody who looks at such a definition will already know what operations are present on it, while it’s not clear what operations an EmployeeCollection might provide.

I would switch to EmployeeCollection when I want to add behavior beyond what List<T> provides (I obviously *have to* switch if I want to add behavior).

This also has the added benefit of not cluttering up the program with types that really don’t need to be there.

Comments (35)

  1. Tim Danner says:

    Your system has failed to properly quote the angle brackets around "Employee" after "List" in the title, so it looks like the question is "List or EmployeeList?" — which has a different feel.

  2. Matt Freiburg says:

    Hmmm… So if, in a subsequent release, you do decide to extend functionality and create an EmployeeCollection class, do you then go back and change the references to List<Employee> to EmployeeCollection for the sake of using a consistent API throughout?

    If so, would it not behoove you to go ahead and create the empty EmployeeCollection implementation right off the bat in anticipation of such a scenario?

    Also, perhaps it’s simply because I’m not yet used to using Generics prolifically, but using EmployeeCollection just seems more cozy than List<Employee> syntactically.

  3. Ryan Cromwell says:

    I would tend to agree with Matt. Setting aside the refactoring support in Whidbey, the signature changes involved could be extensive.

  4. How is this different from the (old) question of whether to use public field variables, or properties? No difference I think, so all standard arguments apply (its all about compatibility, and how much it matters to you).

  5. Sweet! I’ve been wondering this myself … good to hear it from a semi-official source (since the contents of this blog do not represent the opinions of Microsoft Corporation). I would have gone with List<Employee> myself so I don’t have to make a new file for every collection (I also dislike putting multiple, unrelated classes in the same file).

  6. I would agree with Matt. One additional thing to remember: generics are not CLS compliant. So some languages (the very unpopular one) might not support generics… hence, the SomeCollection class being the only "door" to use your API.

  7. Plus you get the benefit of using pre-tested code instead of writing new, bug-prone code.

  8. Ryan Cromwell says:

    Steve – I think it’s a pretty substantial difference from field/property. Fields and Properties can be syntactically referenced in an identical matter. myObject.Name doesn’t tell you whether it is a field or property. The definition of an instance does though. List<Employee> would physically need to be changed in the source in order for you to start using a EmployeeCollection.

  9. Tim says:

    I’d prefer List<Employee>, just for the fact of not adding another type that does the same thing. Unless you look up the class declaration, EmployeeCollection is not as obvious. What kind of collection, list, tree, hash,…? You do know what the collection is with List<>.

  10. Jason Dossett says:

    I think the fact that EmployeeList from the title became EmployeeCollection in the post has created a red herring for some people choosing List<Employee> because of the ‘collection’ ending of EmployeeCollection.

    Would your answers be the same if the choice was (as titled), List<Employee> vs. EmployeeList?

    Wouldn’t most (all?) the arguments for the C++ use of typedef’ing templates apply here? Now that I think about it, what happened to typedef?

  11. LeeB says:

    Jason I think you are right that there has been some confusion over naming in this post.

    I prefer the use of EmployeeCollection rather than Collection<Employee> or EmployeeList over List<Employee>. I would tend to use xList for classes inherited from List<x> and xCollection for classes inherited from Collection<x>.

    To me it’s all down to consistency: as soon as you specialise one class by adding an additional method you have to give it a class name (eg. EmployeeCollection). Even if only one or two classes contain additional members you would end up with an inconsistent library if you were to treat the unspecialised as Collection<Timesheet>.

    If your library contains EmployeeCollection, Collection<Timesheet>, Collection<Job>, CustomerCollection, etc then it becomes impossible to predict what a collection of Invoices would be called – is it InvoiceCollection or Collection<Invoice>? – the actual type name now depends on whether this is a specialised collection.

    As has been mentioned, this makes any declaration which uses Collection<Employee> fragile as the class name may need to change in the future to accomodate specialised behaviour.

  12. Eric says:

    I chose EmployeeCollection because that’s the BCL naming pattern for a collection of employees.

  13. MartinJ says:

    I thought that you were supposed to use xCollection when you implement ICollection (or inherit a collection). But, xList is also a good choice. I wonder what would happen to ArrayList, if FxCop wasn’t happy.

  14. Darren Oakey says:

    I throw my vote in for the class EmployeeList : List<Employee> – for a number of reasons:

    a) as pointed out above – it’s extensible. We WILL at some point want to add some employeelist specific functionality. If we’re using the template directly, then we have a major operation to retrofit this.

    b) It’s changeable. I think people get stuck in the trap of thinking about things in terms of the mechanics of code – rather than the INTENT of code. Day one, I need a list of employees, so I quickly make an EmployeeList class which is just a List<Employee> – works for my current situation.

    There’s no reason why next week, I shouldn’t be able to change EmployeeList to some other sort of collection – a hashtable perhaps? A dictionary? It’s VERY likely I’ll want to do that sort of thing at some point.

    c) templates get very ugly very quickly if their heads aren’t cut off – eg, would you rather use:

    > Filtered<Synchronised<List<Employeee>>, VipFilter> x = new Filtered<Synchronised<List<Employeee>>, VipFilter>( company.Employees );

    or

    > VipEmployeeList x = new VipEmployeeList( company.Employees );

    d) If I want to produce code for other languages, or for COM – EmployeeList will always work…

    The BIG, and ONLY disadvantage of this approach is CONSTRUCTORS. We all know that constructors should be inheritable (if and only if no constuctor is defined in the child class) – but at the moment we don’t have this ability. We also don’t have a typedef instruction. That means that EmployeeList has to duplicate each constructor in List<> – and it won’t hold up if we change List<>.

    (Of course, we all should start lobbying for CORRECT behaviour in constructor inheritance, and this problem completely goes away :))

  15. Matthew W. Jackson says:

    "d) If I want to produce code for other languages, or for COM – EmployeeList will always work… "

    If EmployeeList inherits from List<Employee>, it cannot be CLS compliant, and it won’t necessarily work in other languages. I don’t know about COM, either. Can anyone confirm or deny that it will work when exported to COM?

    You can implement generic interfaces and still be CLS-compliant, but you can’t inherit a generic class. Unfortunately interfaces won’t solve the problem (unless we had automatic interface delegation to a private member).

    It’s a shame that you can’t define closed types of generics with a typedef and allow non-generic-consuming languages be able to use them.

    This would also let you close generic structs, which you can’t do via inheritance. I imagine that it’d be useful to define a struct Complex<T>, and have a typedef ComplexSingle for Complex<Single> and ComplexDouble for Complex<Double>.

    This would also help with the current lack of operator support in generics (or lack of interfaces for such operations on the primitive types). Right now, you can make a Complex<T, O> where O : IOperations<T>, but it’s too combersome to force people to use Complex<Single, SingleOperations>. With a typedef, you could define ComplexSingle, export it, and encourage people to use it instead of the cumbersome version. Of course, a typedef should be compatible with its expanded version, just as int! and Nullable<int> are compatible.

    I’m aware that "using" can do something similar to typedefs, but a public typedef in a library could help keep a consistant name for a closed generic type.

  16. Matthew W. Jackson says:

    *correction*

    int? and Nullable<int> are compatible.

    I’ve been thinking too much about Eric’s other post.

  17. Tim says:

    Jason, you are correct. I based my comments off the contents of the post, not the title. But to answer the question, I’d still prefer List<Employee> over EmployeeList.

    I have a question on this:

    Let’s suppose Employee is an abstract class. HourlyEmployee and SalaryEmployee are the implemenations of Employee. If I have

    class EmployeeList : List<Employee> {}

    can I then do

    EmployeeList l = new EmployeeList(company.HourlyEmployees);

  18. Thong Nguyen says:

    Hmmm… So if, in a subsequent release, you do decide to extend functionality and create an EmployeeCollection class, do you then go back and change the references to List<Employee> to EmployeeCollection for the sake of using a consistent API throughout?

    Not really. You’d simply make EmployeeCollecton extend List<Employee>. Exisiting code won’t need to change unless they want to use the new features of EmployeeCollecton (in which case they’re changing already).

  19. Eric Newton says:

    Tim: should you really care if EmployeeList is a hash,dictionary,or list based structure? shouldnt you just use EmployeeList and not care?

    Matthew Jackson: You bring up a good point about COM handling of List<Employee>.

    Lets just say I was very disappointed that generics werent CLS compliant from the get go. So now generics become VB.Net/C# only, until these other languages [Cobol.Net? / Perl.Net?] all correctly handle the generics syntax.

  20. DanP says:

    After reading all of these very thoughtfull ideas about which path to follow I’m still a bit puzzled.

    First of all I agree with Eric on that the usage of List<Employee> doesn’t clutter the application but on the other hand generic/template code really looks ugly 🙂

    Secondly I prefer to keep the naming convention from the framework intact and therefore the EmployeeList/Collection approach is more attratictive …

    Hopefully Eric will bring these comments back to Ms and maybee we will se a new topic below "Programming with the .NET framework" called something like "Grouping data using Generics"

  21. Tim says:

    Eric, yes, you should care. Hashs, dictionaries, lists, and arrays are all groupings of objects, true. But they implement the group in different ways. Would you iterate through each member of a hash? Can you find a match to a member in an unsorted list or array as fast as a hash?

    If you don’t care about the type of collection, why have different types?

    BTW: your link is broken.

  22. I’ve been working with Robert Swirsky ( http://www.robert.to/ ) on recoding some large C# applications to use the Generic Types.

    In most cases, it has shortened our code considerably, and made it more readable.

  23. Arthur Gilbert says:

    I would not say EmployeeList. Instead, I would say Employees. From a modeling perspective, the requirement is that you need to be able to group N employees. You can use a Hashtable an Array or a List, but that is an implementation issue, not a design issue.

  24. Kannan Goundan says:

    You probably wont run into this problem if you have simple type inference for local variables:

    var names = employees.Keys;

    The variable ‘names’ is enough information. You don’t need an explicit type annotation. The compiler already has this information.

  25. I Got Rhythm says:

    I’ve just seen a blog entry about C# generics, concerning C#’s lack of typedef s. Actually, C# has a

  26. I Got Rhythm says:

    I&#39;ve just seen a blog entry about C# generics, concerning C#&#39;s lack of typedef s. Actually, C#

  27. I Got Rhythm says:

    I&#39;ve just seen a blog entry about C# generics, concerning C#&#39;s lack of typedef s. Actually, C#