Question

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?

Was it helpful?

Solution

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

OTHER TIPS

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top