Share via


List 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

  • Anonymous
    August 17, 2004
    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.

  • Anonymous
    August 17, 2004
    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.

  • Anonymous
    August 17, 2004
    Thanks, Tim.

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

  • Anonymous
    August 17, 2004
    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).

  • Anonymous
    August 17, 2004
    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).

  • Anonymous
    August 17, 2004
    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.

  • Anonymous
    August 17, 2004
    The comment has been removed

  • Anonymous
    August 17, 2004
    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.

  • Anonymous
    August 17, 2004
    The comment has been removed

  • Anonymous
    August 17, 2004
    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?

  • Anonymous
    August 17, 2004
    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.

  • Anonymous
    August 17, 2004
    I chose EmployeeCollection because that's the BCL naming pattern for a collection of employees.

  • Anonymous
    August 17, 2004
    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.

  • Anonymous
    August 17, 2004
    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 :))

  • Anonymous
    August 17, 2004
    "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.

  • Anonymous
    August 17, 2004
    correction
    int? and Nullable<int> are compatible.

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

  • Anonymous
    August 17, 2004
    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);

  • Anonymous
    August 17, 2004
    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).

  • Anonymous
    August 17, 2004
    The comment has been removed

  • Anonymous
    August 17, 2004
    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"

  • Anonymous
    August 17, 2004
    The comment has been removed

  • Anonymous
    August 18, 2004
    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.

  • Anonymous
    August 18, 2004
    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.

  • Anonymous
    August 18, 2004
    The comment has been removed

  • Anonymous
    November 06, 2006
    I've just seen a blog entry about C# generics, concerning C#'s lack of typedef s. Actually, C# has a

  • Anonymous
    March 10, 2008
    PingBack from http://manish24.wordpress.com/2008/03/11/net-frequently-asked-questions/

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

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

  • Anonymous
    June 15, 2009
    PingBack from http://einternetmarketingtools.info/story.php?id=15728