Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C#: Iterator vs function returning IEnumerable

Tags:

c#

Let's say a have two methods:

IEnumerable<int> DoSomething1();
IEnumerable<int> DoSomething2();

that modify the state of my object. I don't know if the function uses yield inside or just returns a List<int>.

And then I'd like to take the output and pass to two other functions:

void SendToUser(IEnumerable<int> values);
void PrintOut(IEnumerable<int> values);

Then just based on the function interface (DoSomethingX) I cannot say if this is a valid operation or not:

var values = DoSomethingX();
SendToUser(values);
PrintOut(values)

Because in the case of iterator it will result in calling DoSomethingX twice.

Is this some kind of inconsistency or I'm using iterator/IEnumerable in the wrong way? Where is the problem?

like image 367
user2146414 Avatar asked Jul 07 '26 10:07

user2146414


2 Answers

If a method returns IEnumerable then you should only rely on the fact that it is iterable, nothing more, as the implementation of that method is subject to change.

If you have control over the method and know that consumers require a more specific type, then return a more specific type.

If you don't have control and need to implement list behaviour, you could always convert the IEnumerable into a list:

var values = DoSomethingX().ToList();
SendToUser(values);
PrintOut(values);
like image 146
Johnathan Barclay Avatar answered Jul 09 '26 04:07

Johnathan Barclay


Read about CQS (command query separation): Wikipedia

In short, there are 2 types of methods:

  1. commands, e.g. void DoSomething(string data) - they change state of your instance
  2. queries, e.g IEnumerable<Person> GetPeople(Filter filter) - which does not change state, they just return some data

Sometimes commands can return value, i.e. PersonID CreatePerson(...);

So if you refactor your code to:

void DoSomething1();
void DoSomething2();
IEnumerable<int> GetData();

it will solve your problem.

The IEnumerable type is just an interface that allows you to iterate over some elements. You don't have idea what is inside concrete implementation.
Usually implementation of IEnumerable should not have any side effects, i.e. changing state of some objects.

If you are dealing with IEnumerable that changes state, you can always materialize it using .ToList() LINQ extension. Then you can pass it to any method w/o any extra side-effects.

like image 38
apocalypse Avatar answered Jul 09 '26 03:07

apocalypse



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!