1

Below is a sample code. My loop is only looping once even though there are three items in it. items[0].Duration is only returning the top item added. It is not looping through the collection.

Any ideas?

public class DurationModel
{
    public string Duration { get; set; }

    public IEnumerable<List<DurationModel>> GetDurationItems()
    {
        List<DurationModel> durationItems = new List<DurationModel>();

        durationItems.Add(new DurationModel()
        {
            Duration = "1 Day"
        });

        durationItems.Add(new DurationModel()
        {
            Duration = "1 Week"
        });

        durationItems.Add(new DurationModel()
        {
            Duration = "1 Month"
        });

        yield return durationItems;
    }
}

public class MyForm
{
    private ObservableCollection<string> _durationItems = new ObservableCollection<string>();
    private IEnumerable<List<DurationModel>> _durationModel = new DurationModel().GetDurationItems();

    public MyForm()
    {
        GetData();
    }

    private void GetData()
    {
        foreach (var items  in _durationModel)
        {
            _durationItems.Add(items[0].Duration);
        }
    }   
}
RBT
  • 24,161
  • 21
  • 159
  • 240
CipherIS
  • 93
  • 1
  • 1
  • 8
  • The "common idiom" for using `yield return` from *an existing collection*: `foreach (var item in durationItems) yield return item;` (ie. for each item, yield it separately.) Of course, in this case yield-return can normally be avoided.. – user2864740 Jan 16 '18 at 23:03
  • I don't think this is a duplicate, but it may be helpful to have a look at [this question and top answer](https://stackoverflow.com/questions/39476/what-is-the-yield-keyword-used-for-in-c). – Drew Kennedy Jan 16 '18 at 23:05
  • 1
    tl;dr: - Your `GetDurationItems` returns an `IEnumerable` that contains a single item - and that item is a list that contains three instances of `DurationModel`. – Zohar Peled Jan 18 '18 at 15:14

2 Answers2

10

With yield return durationItems; you are returning just one single item of type List<DurationModel>. The list implements IEnumerable<DurationModel> or, in other words, is an IEnumerable<DurationModel>. Therefore, the return type must be IEnumerable<DurationModel> and not IEnumerable<List<DurationModel>>, which would be suited to return an enumeration of lists of DurationModels.

Change the method to

public IEnumerable<DurationModel> GetDurationItems()
{
    yield return new DurationModel { Duration = "1 Day" };
    yield return new DurationModel { Duration = "1 Week" };
    yield return new DurationModel { Duration = "1 Month" };
}

One item is returned per yield return. Alternatively, you could write

public IEnumerable<DurationModel> GetDurationItems()
{
    // This works because arrays implement IEnumerable<T>.
    return new DurationModel[] {
        new DurationModel { Duration = "1 Day" },
        new DurationModel { Duration = "1 Week" },
        new DurationModel { Duration = "1 Month" }
    };
}

You could use a List<DurationModel> as well.

Note that yield return makes the method pause, remember its state and return. When foreach requests the next item, the method resumes after the last yield return. (See also Behind the scenes of the C# yield keyword by Lars Corneliussen)

With the first method, the items are created as they are used in the loop. With the second one they are all created when the loop starts.

yield return allows you to generate enumerations algorithmically, without storing the items in a collection

public IEnumerable<int> ThousandSquares()
{
    for (int i = 1; i <= 1000; i++) {
        yield return i * i;
    }
}

public void PrintSquares()
{
    foreach (int n in ThousandSquares()) {
        Console.WriteLine(n);
    }
}
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
1

Why are you using yield return durationItems; instead of return durationItems;. You should add _durationModel = new DurationModel().GetDurationItems(); in the constructor and after that call getData

Kalamarico
  • 5,466
  • 22
  • 53
  • 70