ASP.net C# – List vs IList

Sorry for reopening this old debate, but I have been struggling with getting my head around this concept but came to a conclusion of my own.

The problem

I build lots of websites and in work we have our own internal CMS engine that works the way we work.  It has the following (simplified) structure:

WebUI—–¬
|               |
Services—-|—-Entities (used in both WebUI and Service layer)
|
Data

Now everything I have read lately pushes me to programme to an interface – including my data layer “just in case some random person brain farts that we should change to MySQL” (this will never happen as I make the decisions).  If I were to program to an interface the 20 or so plus classes would each have their own interface, the 30+ entities would each have their own interfaces, and I would have SO much code, that I would no longer know what am doing e.g.

ICMS_PageService service = new CMS_PageService();
service.FetchById(id);

And I have seen code like that.  Or the FactoryPattern:

ICMS_PageService service = new SiteFactory().FetchPageServiceInstance(); // or whatever it was called
service.FetchById(id);

which is more understandable, in that you now only have 1 place to change the implemenation – so change the CMS_PageService implementation, update the SiteFactory as required, and your whole site continues to work as normal.  I get that, I quite like that in some respects.  What I don’t get is the IList vs List stuff.

Listing about

I read in another blog post:

“I already had cases where one returned a List as IList. But because of the IList interace I could not sort the result directly.”

Yeah, that’s annoying.  If say I have this:

ICMS_PageService service = new SiteFactory().FetchPageServiceInstance(); // or whatever it was called
IList<ICMS_Page> pages = service.FetchAll();

I cannot use pages as I would expect.  I want to pages.ForEach(page => stringBuilder.Append(page.Title)); Instead with IList I have to cast and muck around to get the same result (not that much more but enough to make the .ForEach a pointless addition if we all programmed to an interface).

Unit Test and Mocks

But I also understand that if you do programme to an Interface then you can easily test your code, someone else can mock things up, and you can make sure your whole code base is working dead simple.  But to me, that’s over kill for most things but complicated web/desktop apps – but take the idea of interfaces seriously if it’s complicated beastie you are working with.

Chisel vs Pneumatic Drill

So then, maybe my point is “right tool right job”?  If you are creating simple applications, that live and die real quick, say within a year or 2, then is there a need to add an extra few days/weeks doing all this overhead?  But with large apps that will take a year or 2 to build, then it might be more important.

Also if you have a strong code base that you have built up over time, that you know works, but doesn’t programme to an interface, should you retro fit things?

Everything I read screams at me to Unit Test, Mock, Programme to Interfaces, and all the reasonings are to make it easier to change things when requirements change…so ask your self before you listen to all of them, do you expect to move away from SQL Server?  Do you think that the changes in requirements are going to be so game changing that there is a need to make everything an Interface – which in most cases will cause you just as much problems e.g. add a new field in the CMS_Page table, will require a chance in the concrete CMS_Page class and the ICMS_Page interface before you will have access to the property in the WebUI.  Bit too much work for my liking.  Or if you add a new method to the CMS_PageService you have to do that to the interface as well, before it’s usable.  And if you have a lot of people using the interfaces elsewheres, and you change it, then you break lots of people’s code.  Conversely by not using Interfaces so often, or using them in a generic smart way, then adding a new method won’t break much of your existing code, the new method or property will just appear ready to use.

So use IList and have to cast and convert often in your code, while not getting access to the lovely new features in the generic List object.  Or use the List object, make a lot of purists angry but work the way you expect things to work.

Conclusions

So my conclusion is to use interfaces smartly and sparsely, if you are building a small to medium website.  But if a large app that will take years to build with tonnes of developers, then the use of interfaces in such a way maybe be warranted, locking down what code can do with your data.  But I would love someone to tell me, without using the “if things were to change due to client requirements” arguement, why I should use Interfaces all over the place in every project…

13 thoughts on “ASP.net C# – List vs IList”

  1. I ain’t grabbing you anywhere matey 😀

    I get what you are saying though. I get the whole loosely coupling code when on large projects, but if you are on a small to medium size website, then is it not overkill to have all that extra overhead in coding? Right tool right job n that?

    As I said, if I have IList but want to use the .NET generic List stuff like .ForEach(), then am scuppered. There is no way to go back to that without casting, and then you have to wrap in try/catches or (page is List) before you can start to use it as you want, and that again is overhead.

  2. The .foreach should be coded against Ienumerable. Not ilist 😉

    Anything like array list etc all implement ienumerable at their core

    Following me?

  3. P.s if it’s web the right tool right job can be only one thing. Ruby on rails. Nothing else comes close.

    I’ll go over that in the pub in Kowloon too 🙂

  4. But IEnumerable doesn’t have a .ForEach, neither does an IList. Both of which you need to do something like this:

    // find all pages with the title is like “Colin”
    IEnumerable iPages = new CMS_PageService().FetchAll();
    List
    found = new List();
    foreach (CMS_Page page in pages)
    {
    // blah this is baws!!
    if(page.Title.Contains(“Colin”))
    found.Add(page);
    }

    but with .NET’s generic List object you can do this:


    // find all pages with the title is like “Colin”
    List pages = new CMS_PageService().FetchAll();
    var tmp = pages.Find(page => page.Title.Contains(“Colin”));

    and that is much much nicer! No? So why do I want IList and IEnumberable for all my service classes, when I don’t expose them further than my own websites?

  5. Ok, but not really viable reason coco.

    MS provide some helpers for you, but 99% of the time they miss the point.

    Here we have an example of what I said on the other comment.

    using System;
    using System.Collections.Generic;

    namespace NinjaTools.Helpers
    {
    public static class EnumerableExtensions
    {
    public static IEnumerable Each(this IEnumerable collection, Action action)
    {
    foreach (var item in collection) action(item);
    return collection;
    }
    }
    }

  6. p.s why on earth would you choose filtering on code side to db side?

    Massive performance loss. Find the boundaries and stick with them.

  7. public static IEnumerable Find(this IEnumerable collection, Action action)
    {
    foreach (var item in collection)
    If (action(item))
    yield return item;

    Your find method would look something like above. However ipnonr ain’t too good for writing code lol. I’ll send u better one tomorrow
    }

  8. Massive performance loss. Find the boundaries and stick with them.

    I did a test tonight. I have a database table with 7840 towns and villages from different countries around the world. My code I have set up so that I can save into cache quite easily.

    My first test was to iterated around a list in cache 10,000 times to find a random selection with 2 characters in it’s town name:

    for (int ii = 0; ii < 10000; ii++) { searches = new RM_TeacherService().FetchAllSearches(); contains = alpha[rnd.Next(0, 25)] + alpha[rnd.Next(0, 25)]; output = searches.FindAll(search => search.Town.Contains(contains));
    }

    This use the .NET built in FindAll on the objects I retrieved from the database, and then after the first call, the .NET cache object. It takes on average 123 seconds to run. I thought that was a bit piss poor really. I got upset thinking Dave was right again… So I did this to for his side of the argument:

    for (int ii = 0; ii < 10000; ii++) { contains = alpha[rnd.Next(0, 25)] + alpha[rnd.Next(0, 25)]; searches = new RM_TeacherService().FetchAllSearches(contains); } Where FetchAllSearches this time takes the 2 character and goes the SQL Database each time, only returning what it gives me. What made me laugh was on average it was 140 secs to repeate 10,000 times. So the in memory List was 17 seconds faster (divide that down by the 10,000, each iteration is 0.0017seconds faster. So really it's not a performance issue, unless you are doing massive amounts of searches and stuff and for some reason need to hit your database 10,000 real quick. However this was an extreme case, with 7840 items. That would be a very unrealistic thing to do, and it is better with data sets that never change, and are real small e.g. lists of Areas in Scotland. But the difference as seen can be negligable, it's just a matter of choice if your database server is already getting massively hit.

  9. Can I ask what you mean by “MS provide some helpers for you, but 99% of the time they miss the point.”?

    I find the new Generic list built in methods real helpful, and it means you don’t need to write your own versions of it to extend the IList, IEnumerable etc etc, which when you think on it, would mean everyone would need to have access to the DLL with the extension method, or they could just use the List object 🙂

    I do get all the idea of good use of iterfaces, and especially when it comes to DI – the idea of being able to change the logging mechanism of an error handler or a shopping cart is quite nice and lends itself easily to the loosely coupled code. But I cannot foresee myself changing the database from SQL Server to MySQL without needing to change to PHP 😛

  10. While reading the MVC2.0 book, I noticed the AsReadOnly() method, they returned through as an IList so I came back to my code, set up the methods to IList and tested it. Not a single bit of difference. I then put on the .AsReadOnly() when returning the items, and guess what. The first code example above was 40 secs faster this time around! I couldn’t believe what I was seeing so had to do it a few times!! And that was with:

    if(searches is List)
    output = (searches as List
    ).FindAll(search => search.Town.Contains(contains));

    so I could use the FindAll() method 😀 However what I will have to give Dave credit for is that he made me try other methods and it turns out FindAll() isn’t all that efficient. By changing the code around to use .AsReadOnly() IEnumberable objects and iterating around them via a foreach call, actually took the time to iterate 10,000 times over an in memory object down by 50 secs from the original test, in comparison to the straight from SQL Server.

    So ok, there are much performance gains to be had. But I will caveat this with, if you are building a website, then using the built in .NET generic List method will save you time coding in the short term, and to go back to the post “right tool right job”? If you are building a banking app, that will easily be iterating around 10,000,000 rows of a database, and possibly in memory. then the code Dave uses by the looks of it, will save you lots of processing time. But if you are building a website that is really just a list n detail, then you will save more development time using the built in stuff.

    Performance wasn’t my key thought on this post, but what Dave has made me test and therefore find, is there is a good reason which isn’t just “if things were to change due to client requirements” it’s possible massive saving of processing time.

    Any other reasons?

  11. You can look at this argument from several angles including the one of a purely OO approach which says to program against an Interface not an implementation. With this thought, using IList follows the same principal as passing around and using Interfaces that you define from scratch. I also believe in the scalability and flexibility factors provided by an Interface in general. If the implementation of the class returning IList needs to be extended or changed, the consuming code does not have to change. However if a concrete implementation and List was returned, then changing the classes implementation would cause the calling code to need to be changed as well. This is because a class adhering to IList guarantees a certain behavior that is not guaranteed by a concrete type.

    I see your points though and agree the additional casting back to a List to use the operations needed and checking whether the cast was successful can be tedious. I wouldn’t label the ‘size’ of the project as the hard line in the sand factor on using Interfaces; we all know the ‘small’ projects that balloon into the enterprise projects and those are the ones built with the worst foundation because it was originally thought of to be a ‘small’ project. Rather, look at potential scaling of the application, and it ‘could’ blossom into something larger, and then heavily consider a more OO design using Interfaces like IList.

Leave a Reply

Your email address will not be published.