1

I've read articles that say use ICollection<T> if you want the functionality of IEnumerable<T>, but also want the Count property.

However since the extension methods in System.Linq.Enumerable provide methods such as ElementAt(), why wouldn't you just use an IList<T> instead, since that uses an indexer?

Seems to me that ICollection<T> can do what IList<T> can do, just in a much more verbose and less readable way.

What scenario would it be more readable/more efficent, more adhering to SOLID principles, or some how better in any way to use ICollection<T> over IList<T>?

EDIT:

The duplicate question's answers do not answer my question since they avoid talking about the fact that ICollection<T> can do what IList<T> does but in a much uglier way.

If they both do the same thing, why not just use the cleaner IList<T>?

I received much better answers here: https://www.reddit.com/r/csharp/comments/dl9xao/why_use_icollectiont_over_ilistt/

David Klempfner
  • 8,700
  • 20
  • 73
  • 153
  • So you're saying that I can call your method or read your property, get back a list, and then start adding elements to it? – Lasse V. Karlsen Oct 14 '19 at 10:44
  • 2
    The 3 types involved in your question tells me different things. IEnumerable tells me that I will get a collection of items. ICollection tells me I will get a collection of items that guarantees easy and quick access to the number of items in it. List tells me I will get a collection I can manipulate. You will have to decide which level is appropriate in each case. – Lasse V. Karlsen Oct 14 '19 at 10:46
  • But ICollection gives you a collection you can manipulate as well. ICollection just seems like it has all the same functionality as IList, just not as clean. – David Klempfner Oct 14 '19 at 10:47
  • 1
    Unfortunately, I feel this question is off topic because it indirectly asks for peoples opinion and suggestion. There is no fixed solid single answer that says "return this when that otherwise this other thing". I have several opinions just on whether you should return one or the other, depending on a lot of factors but it boils down to being *my* opinions. – Lasse V. Karlsen Oct 14 '19 at 10:48
  • You're right, but it doesn't have to be a list. It can be something else that allows you to manipulate it. I guess I confused it with IReadOnlyCollection which is the one I use, sorry about that. – Lasse V. Karlsen Oct 14 '19 at 10:48
  • Where should I go to ask a question that involves getting people's opinions? – David Klempfner Oct 14 '19 at 10:49
  • Possible duplicate of [Returning 'IList' vs 'ICollection' vs 'Collection'](https://stackoverflow.com/questions/9855693/returning-ilist-vs-icollection-vs-collection) – Michael Sander Oct 14 '19 at 10:49
  • To get peoples opinions I always feel the chat rooms here would solve that. There might be other sites in the network that handles it better though, but I tend to go to the chatrooms. You can find them top right in the small Stack Exchange button. – Lasse V. Karlsen Oct 14 '19 at 10:50
  • My opinion about the types involved is that you should be as open as possible in input parameters/positions, which means favor IEnumerable over ICollection/List, and as explicit as possible in output parameters/positions. For instance, if your method *constructs* a new list and fills it with new data, what harm does it do to return it? But also consider API evolution, do you want to limit yourself to *always* have to return a list in the future? No easy discussions I'm afraid. – Lasse V. Karlsen Oct 14 '19 at 10:51
  • 1
    I think your question is actually a duplicate and is addressed by those answers (broadly) - It's a use case scenario. One such scenario is using `IDictionary` or `dynamic` types (`System.Dynamic.ExpandoObject`) for that matter. – Brett Caswell Oct 22 '19 at 22:11

3 Answers3

2

If you're looking at this from an overhead perspective, I think you're best bet is the intermediary between the two, ISet<T> and it's implementation of HashSet<T>.

Set's are often overlooked, but are extremely efficient in determining "ownership" and save space by virtue of not relying on keys since they don't concern themselves with ordering.

EDIT (2020/11/18) - It's important to note that upon adding an item to the HashSet, it's HashCode will be computed. The cost of this might be expensive, and thus complete negate any performance benefits you might gain from faster lookups.

The important difference is that Add(), Remove() and Contains() all become o(1) (vs the typically o(n) cost of IList<T>.

There is also SortedSet<T> if ordering becomes an issue.

Here's a great article explaining this is much better depth than I can. An important snippet:

The HashSet<T> is the set of choice if you want the fastest possible lookups but don’t care about order. In contrast the SortedSet<T> will give you a sorted collection at a slight reduction in performance.

pim
  • 12,019
  • 6
  • 66
  • 69
  • 1
    Some misleading information here -- hashsets, while excellent for fast lookup, are not always better. You need to keep in mind that adding something to a hashset requires the item's hash to be computed, which, depending on the particular use case, may completely negate any lookup performance benefits. Understand it and use it wisely... – Igor Pashchuk Nov 17 '20 at 05:09
  • If you read carefully I don't claim that HashSet's are a silver bullet as your implying. I specify the value they can bring in a particular use case, even outlining the cases where there are optimal. – pim Nov 17 '20 at 17:31
  • Upon rereading it carefully, I still do not see any implied drawbacks of the HashSet. But, this should be easy to remedy. I'd be happy to upvote once you update it to give a more balanced view. HashSets are indeed frequently overlooked and your contribution on this point is very welcome! – Igor Pashchuk Nov 17 '20 at 21:52
  • 1
    @IgorPashchuk updated to include your note about hashcodes – pim Nov 18 '20 at 16:46
2

The answer is highly subjective. It's more about how much you need.

  • If all you need is to loop through all the items, prefer IEnumerable<T>
  • If you need to manupulate the collection (Add, Remove etc.) ICollection<T> should be used.
  • If you are going to use Index frequently, use IList<T>.
  • If you are planning to do all sort of manipulation go ahead and use List<T>.

However in those cases, there are IReadonlyCollcetion<T> and IReadonlyList<T>, this makes the returned collection immutable and again should come after IEnumerable but preferred over ICollection<T> and IList<T>.

The end goal always is to use as abstract types as possible. This is based on the principles Code for the interfaces not for the implementation.

Edit: For this question I would say need of indexing is the primary factor of preferring one over other.

Code Name Jack
  • 2,856
  • 24
  • 40
  • Controversial opinion. I ask for `IReadOnlyCollection` when I mean to iterate the enumerable more than once. I also make enumerables that can't be iterated more than once. – Joshua Nov 17 '20 at 05:00
  • Multiple enumerations as well as unordered enumeration `IReadOnlyColection` will really be better. analogous answer would be, if it is foreach always IEnumerable works, if a for loop, then `IReadOnlyCollection`. But again even though for loop can do everything that foreach does, we use foreach wherever possible. – Code Name Jack Nov 17 '20 at 05:05
-1

The short response is that you can just use IList for any list of elements. In fact, IList implements ICollection and ICollection implements IEnumerable. You're able to decide what level of abstraction you need according to the context.

See this link for details.

Christopher Moore
  • 15,626
  • 10
  • 42
  • 52
Fran
  • 181
  • 8
  • 1
    well... I'm not going to downvote you (given your rep), but the question statement here reflects the title: "What scenario would it be ... better ... to use `ICollection` over `IList`. So, this answer doesn't really relate to the question, nor inquiry. – Brett Caswell Oct 22 '19 at 22:42
  • Also, you should probably use terms like 'implements' or even 'derives' instead of subinterface to relate to the OOP material we're more accustomed to. Additionally, It questionable whether you should think of interfaces in a hierarchical manner. I haven't actually delved into it enough to give certainty here, but it comes down to whether you're able to determine, during runtime, whether there is a derived interface of the base interface of an instance of some type; if it's possible to do that, I could see merit in thinking in those terms. – Brett Caswell Oct 22 '19 at 22:49
  • Thanks @brett-caswell for your comment. Updated the answer accordingly. – Fran Oct 23 '19 at 10:06