1

Approach 1:

class myClass
{
   List<SomeType> _list;

   IENumerator<SomeType> GetEnumerator()
   {
      foreach(SomeType t in _list)
        yield return t;
   }
}

myClass m = new myClass();
List<SomeType> list;
...
foreach(SomeType t in m)
  list.Add(t);

Approach 2:

class myClass
{
    public List<SomeType> _list {get; private set;}
}

myClass m = new myClass();
...
List<SomeType> list = m.list;

Which approach is better? If second then could you please show me real-proof usage of yield return?

Ivan Prodanov
  • 34,634
  • 78
  • 176
  • 248
  • 3
    Well, if you want an Enumerator, use the first one, if you want a list, use the second one. These are two different things. http://stackoverflow.com/questions/17125/what-are-real-life-applications-of-yield – looper Nov 22 '12 at 14:19
  • A `List` already has a `GetEnumerator` implementation??? – Jodrell Nov 22 '12 at 14:26
  • What are you actually asking, when could I use `yield return`? – Jodrell Nov 22 '12 at 14:29

3 Answers3

3

Neither.

If you want an enumerator, and already have an underlying IEnumerable type (List implements IList which extends IEnumerable), then just return it like that:

public IEnumerator<SomeType> GetEnumerator ()
{
    return _list.GetEnumerator();
}

Otherwise, if you actually need a list, i.e. random access using indexes, then return an IList; and if you actually want to return its internal implementation type, i.e. List, then you can just make it an accessible property. Note though, that a private setter does not prevent modifying the list (adding or removing items etc.). If you want that, return a read-only list instead:

public IList<SomeType> List
{
    get { return _list.AsReadOnly(); }
}

Regarding yield

could you please show me real-proof usage of yield return?

yield return is useful, when you actually have a generator, when you actually need to generate the next item. A simple example would be a random number generator which provides you with another random number, as long as you keep asking it. There is not necessarily an end to it, but you might not know the amount of numbers before starting.

Another common usage would be anything that retrieves the data from some external source. For example a list of items from a webservice. Before you don’t know how many items there are, and you don’t necessarily know how many items you actually want (as you might want to display it in an endless display, showing one at a time). In that case, you could do it like that:

IEnumerable<Item> GetItems()
{
    while (Service.HasMorePages())
    {
        foreach (Item item in Service.GetNextPage())
        {
            yield return item;
        }
    }
    yield break;
}

GetNextPage would always return a list of N items at a time, and you would get the next one whenever you want more items than you have already received.

poke
  • 369,085
  • 72
  • 557
  • 602
3

A class with a collection-property is usually best done as a list, so that it can be iterated multiple times, and mutated. That is not possible for an enumerator, which represents just a sequence. Typical uses of enumerators might be:

  • filtering data on the fly (such as Enumerable.Where)
  • reading individual items sequentially from a file that contains multiple records, without loading them all at once
    • or network socket
    • or database server
  • providing a forwards-only, read-only wrapper over a sequence of data
  • etc
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
1

The options are without bound,

public IEnumerator<int> FibonnaciSeries()
{
    int a = 1;
    int b = 1;

    yield return 1;
    yield return 1;

    while (true)
    {
        var c = a + b;
        a = b;
        b = c;
        yield return c;
    }
}

Is one trivial example that comes to mind, is the Fibonnaci Series real world?


This is not the most efficient implementation possible.

Jodrell
  • 34,946
  • 5
  • 87
  • 124
  • 1
    you'd be amazed just how often this doesn't come up in day-to-day real-world programming ;p – Marc Gravell Nov 22 '12 at 14:36
  • @MarcGravell I must admit, I've not been thirsting for its addition to the framework. – Jodrell Nov 22 '12 at 14:40
  • @Jodrell If you add Fibonacci, you have to add lots of other common algorithms as well; and then you would have a problem of a never ending discussion of what to add and what not to add. In addition, as you’ve said yourself, it is not the most efficient implementation possible, and for most algorithms “efficient” totally depends on your needs, so it would be hard to add the “perfect” solution anyways. That being said, you do know that Fibonacci numbers have a [closed form](http://en.wikipedia.org/wiki/Fibonacci_number#Closed-form_expression)? – poke Nov 22 '12 at 14:45
  • A implementation with a indexer that supports `BigInteger` is a much more interesting problem but even less everyday and certainly beyond the scope of the question. – Jodrell Nov 22 '12 at 14:45
  • @poke, I fear my sarcasm didn't transfer well in my previous comment. I've only actually ever used the Fibonnaci Series to answer a question on SO. – Jodrell Nov 22 '12 at 14:56
  • @Jodrell Oh well, I did miss the sarcasm, yeah. But it makes sense… ^^ – poke Nov 22 '12 at 19:50