Proper use of iterator blocks

I used to revise the code, and I came across an iterator block implementation that I was not sure about. At the integration level of the system in which the client calls an external API for some data, I have a set of translators that take the data returned from the API and translate it into collections of business units used at the logical level. The general class of translators will look like this:

// translate a collection of entities coming back from an extrernal source into business entities public static IEnumerable<MyBusinessEnt> Translate(IEnumerable<My3rdPartyEnt> ents) { // for each 3rd party ent, create business ent and return collection return from ent in ents select new MyBusinessEnt { Id = ent.Id, Code = ent.Code }; } 

Today I came across the following code. Again, this is a translator class; it is intended to translate a collection into a parameter into a return type of a method. However, this time it is an iterator block:

 // same implementation of a translator but as an iterator block public static IEnumerable<MyBusinessEnt> Translate(IEnumerable<My3rdPartyEnt> ents) { foreach(var ent in ents) { yield return new MyBusinessEnt { Id = ent.Id, Code = ent.Code }; } } 

My question is: is this a valid use of an iterator block? Thus, I do not see the benefits of creating a translator class. Could this lead to unexpected behavior?

+8
iterator c #
source share
5 answers

Your two examples do almost the same thing. The request version will be rewritten in the Select call, and Select will be written just like your second example; it iterates over each item in the source collection, and yield returns the transformed item.

This is a perfectly acceptable use of an iterator block, although of course you no longer need to write your own iterator blocks like this because you can just use Select .

+13
source share

Yes it really is. The advantage of foreach is debugging, so I prefer this design.

+3
source share

The first example is not an iterator. It simply creates and returns an IEnumerable<MyBusinessEnt> .

The second is an iterator, and I see nothing wrong with that. Each time the caller iterates over the return value of this method, yield returns a new element.

+3
source share

Yes, this works great, and the result is very similar.

Both create an object that can return a result. Both rely on a source enumerated to remain untouched until the result is complete (or shortened). Both use deferred execution, i.e. Objects are created one at a time when you repeat the result.

There is a difference in that the first returns an expression that uses library methods to create an enumerator, and the second creates a custom enumerator.

+3
source share

a major difference is included when each code is executed. The first is delayed until the return value is returned, and the second is executed immediately. I mean, the loop for the loop causes the iteration to start. The fact that the class provides a IEnumerable<T> and in this case is delayed is another thing.

This does not benefit from a simple Select . yield Actual power is when there is a condition:

 foreach(var ent in ents) { if(someCondition) yield return new MyBusinessEnt { Id = ent.Id, Code = ent.Code }; } 
-one
source share

All Articles