Search code examples
c#linqienumerablespecflow

Guid value changes when you don't use LINQ "ToList()" with Select() that returns IEnumerable


I have an "Test" class that has an IEnumerable of concrete objects

public class Test
{
    public IEnumerable<MyObject> MyObjects { get; }
}

public class MyObject
{
    public string Id { get; }


    public MyObject(
        string id,
    {
        this.Id = id;
    }
}

When debugging my "Steps.cs" class used by my Specflow feature file, I noticed that the values for "Id" were changing. They were as expected in the "Given" step and I added these to the ScenarioContext

[Given("I have use case (.*)")]
{
    var _test = _retrieveTest.GetMyObjects(useCase);
    ScenarioContext.Current.Add("test", _test); 
}

They were changed when I read them out of the ScenarioContext in the "When" Step

[When("I do something")]
public void WhenIDoSomething()
{
    var _test = (MyProject.Entity.Test)ScenarioContext.Current["test"];         
} 

The solution to stop the values changing was to use the LINQ "ToList()" call when retrieving the object as shown below:

private IEnumerable<MyObject> GetMyObjects(
        string usecase,
        MyProject.Entity.Test test)
    {
        ...
        return testData.Objects
            .Select(Object => {
                var _id = var _id = Guid.NewGuid();

                return new MyProject.Entity.MyObject(
                    _id);
            }).ToList();
    }

Can anyone explain why it is necessary to call ".ToList()" here and without it why the value of "Id" changes in the "ScenarioContext " between the "Given" and "When" steps


Solution

  • Without the .ToList() you have return an Enumerator that is executed everytime you iterate over it. With the .ToList() you materialize the enumerator and have a concrete list.

    See IEnumerable vs List - What to Use? How do they work? for a more detailed answer.