X likes to execute an
IEnumerable
as soon as possible, hence why X is doing it inside of the method.
Whereas
Y is thinking that if you wait until the object is actually needed, using differed execution, you’re eliminating wasted objects in the memory.
They are both wrong. The answer isn't digital, this is, there is no 0 or 1 answer. It depends. Sometimes you must execute a collection and return a non-IEnumerable
.
Such a case would be querying a database. In this scenario you'd open a database connection (or create a context if it's some ORM) and dispose it at the end. If you don't execute it with ToList
or ToArray
etc. you won't be able to do it later. The runtime would wrap your enumerator with an anonymous type containing the context but when the execution leaves the method, the context gets disposed and it'll throw an excepiton the moment you try to get the data. In this situation you should return a non-IEnumerable
type.
The reason the return type shouldn't be an IEnumerable
in this case is that IEnumerable
tells me that the return type is lazy so if I wanted to use it multiple times I'd call ToList
myslef (again) to get the result which would unnecessrily enumerate the collection again.
So, the bottom line is: if you don't have to materialize the result (because you won't be able to get it later when the service/provider is disposed etc), don't do it but be consistent with the API (return types).
When the result value it's materialized I expect you to communicate this fact clearly by using ICollection
, IList
or anything else but IEnumerable
.
As far as your code is concerned you need to answer one question for yourself:
TesscoModel.PricingQuery priceQuery = new TesscoModel.PricingQuery();
Is this line querying a database or a web-service etc.? If your answer is yes, then I'd use ToList
and IList
as a return type so that the user knows, it's safe to query this line multiple times without executing the enumerator because it already run.
IEnumerable<ProductPrice> productPrices = productService.GetPrices
One more example.
What I'm saying is. It should either be
IList<ProductPrice> productPrices = productService.GetPrices(...).ToList();
because GetPrices(...)
is lazy, so I execute it myself.
or GetPrices(...)
is eager and I don't need to do it again.
IList<ProductPrice> productPrices = productService.GetPrices(...);
The same priciples apply to parameters. In your example you execute skus
multiple times: with Any
and with the foreach
loop.
Here, I'd requested an ICollection
or an IList
to tell the caller: Look out! I'll be using your collection more then once (so you might consider materializing it for better performance before givit it to me).