SimoneF
SimoneF

Reputation: 432

Yield keyword behavior in C# 2.0

In a method I yield a custom object which I reuse. later for yielding again.

private IEnumerable<DistributorMonthlyComparisonData> ExtractMonthlyAggregate(String CSVFilepath)
{
    DistributorMonthlyComparisonData unitData = new DistributorMonthlyComparisonData();
    while (!reader.EndOfStream)
        {
            if(something){
                // fill unitData
                }
            else{
                 yield return unitData;
                }
        }
}

In another object in my program I call said method in this way:

List<DistributorMonthlyComparisonData> distribList = new List<DistributorMonthlyComparisonData>();
foreach (DistributorMonthlyComparisonData result in ExtractMonthlyAggregate(percorso))
  {
    distribList.Add(result);
  }

If I don't create in the yielding method, after each yield, a new object

unitData = new DistributorMonthlyComparisonData();

All I get is a List of identical objects.

I am wondering: is this because unitData is being passed as a reference and thus the List is merely a List of references to the same identical object? Creating a new unitData() every time changes the hash of the unitData object being passed?

Please enlighten me. :)

EDIT I am interested in why this is happening. I used to think that the framework is supposed to do copy-on-write on objects, so basically yielding one object then modifying its properties and then yielding it again should result in two different objects being added to the list.

Upvotes: 1

Views: 176

Answers (4)

R. Martinho Fernandes
R. Martinho Fernandes

Reputation: 234614

Creating a new unitData() every time changes the hash of the unitData object being passed?

There is no implementation of GetHashCode(), DistributorMonthlyComparisonData is just a collection of properties.

The default implementation of GetHashCode() makes no guarantees about its return value. So, if you have no custom implementation for it, you should not have any expectations about it.

When you define equality for a type (by overriding Equals) you have to override GetHashCode as well, and guarantee that objects that compare equal have the same hash code.

Upvotes: 0

Novice
Novice

Reputation: 2487

The object initialization will happen only once. The execution will resume from the while loop from the second iteration onwards. That's why the object collection has the same object instances.

Upvotes: 1

Heinzi
Heinzi

Reputation: 172388

I am wondering: is this because unitData is being passed as a reference and thus the List is merely a List of references to the same identical object?

Exactly.

Creating a new unitData() every time changes the hash of the unitData object being passed?

That depends on DistributorMonthlyComparisonData's implementation of GetHashCode().

Upvotes: 2

Sebastian Mach
Sebastian Mach

Reputation: 39109

C# has reference semantics for class types, so you are right about references being returned.

Sidenote about the rest:

yield return/yield break will continue the loop you place them in. Therefore, the code before your loop is only executed once before the loop is entered. You would have to new your returned objects inside the loop.

I.e., you would have to replace

DistributorMonthlyComparisonData unitData = new DistributorMonthlyComparisonData();
while (!reader.EndOfStream) {
    ...

with

while (!reader.EndOfStream) {
    DistributorMonthlyComparisonData unitData = new DistributorMonthlyComparisonData();
    ...

Upvotes: 3

Related Questions