Is it really a best practice to use IEnumerable<T> in method declaration, instead of List<T>?

Method1(IEnumerable<T> collections);

Method2(List<T> collections);

That all depends on what Method1 is doing. If you have this signature:

void Method1(IEnumerable<T> items);

Then when I use your method, you are telling me (through the signature) that you will not be adding to the items but simply iterating over them. In other words, you will be using only the methods of IEnumerable.

However, if the signature is like this:

void Method1(List<T> items);

Then it tells me that you may add, remove items from the list I provide to your method (or any other method exposed by List<T>). Therefore, if I do not want you to add/remove items to my list, I will create a copy of my list and give you the copy. That way my list is safe from you.

Therefore, it all depends on what the method is doing or needs to do. A good practice is to only ask for the minimum--for the most general interface. If all you need to do is to loop through the items, then do not ask for List<T> but ask for IEnumerable<T>.

  • \$\begingroup\$ IList<T>, however, is pretty well always preferable to List<T>. Furthermore, if you need an ordered list but don't need to modify it, use an IReadOnlyList<T>. A less demanding type also gives the caller more options: they can pass a HashSet as an IEnumerable, but not as an IList. \$\endgroup\$ Feb 4 '18 at 18:23
  • 4
    \$\begingroup\$ It's not only about whether someone is going to add something to the collection or not but rather whether the collection is already materialized and I can safely itereate it multiple times or do I have to materialize it myself first. Btw. this question should not have been answered in the first place as it's clearly off-topic for CR. \$\endgroup\$
    – t3chb0t
    Feb 4 '18 at 18:28
  • \$\begingroup\$ @t3chb0t Yes you are right, I should not have answered it but I thought it was on software engineering. As to it being materialized, that is not the receiver's responsibility but the sender's (caller's). If you pass me IEnumerable<T>, and it is not materialized, that is too bad. In other words, to fix that you would not necessarily go into the method receiving it and ensure it only traverses once, but fix it in the caller. \$\endgroup\$ Feb 5 '18 at 12:18
  • \$\begingroup\$ I cannot agree. The method requesting parameters must know wheter it's ok to pass it some collection or a materialized one. If I know that I'll be using it a lot I request it to already be populated. It's not a caller decistion but the callee's. \$\endgroup\$
    – t3chb0t
    Feb 5 '18 at 12:23
  • \$\begingroup\$ t3chb0t But that would be sort of a "secret" and it would need to be documented. And doing that in a public API would be totally insane. It is better to code against interfaces than to code against "secrets" buried in the docs. \$\endgroup\$ Feb 5 '18 at 12:29

Not the answer you're looking for? Browse other questions tagged or ask your own question.