Jay
Jay

Reputation: 2141

Why using yield return here?

I have found the following method in an open source project:

    static IEnumerable<T> Cat<T>(T t) {
        yield return t;
    }

As far as I understand, it does nothing else than returning an IEnumerable<T> containing t. If I am right and it's virtual equivalent to e.g. return new List<T>{t};, what's the purpose/advantage of using yield return here? And if I am wrong, what do I miss?

Full source can be found here.

Upvotes: 3

Views: 249

Answers (3)

Guffa
Guffa

Reputation: 700152

The difference between returning an actual collection and using yield is just the type of the object that you return.

If you return any collection that implements IEnumerable<T>, the actual type of the object returned will be that type. If you for example return a List<T>, the reference returned will be of the type IEnumerable<T> but the actual type of the object that the reference points to is an instance of List<T>.

If you use yield, the compiler will create an enumerator object without a known name. The type of the reference returned will also be IEnumerable<T>, but the actual type of the object that the reference points to will be something that the compiler creates.

For example getting the name of the type of an enumerator created for an integer:

Console.WriteLine(Cat<int>(42).GetType().Name);

will show the internal name that the compiler uses, for example this result that I got from the code:

<Cat>d__5`1

If the function would return a List<int> instead, the type would display as:

List`1

The motivation for letting the compiler create an enumerator for this is probably just that it is shorter than something like this:

static IEnumerable<T> Cat<T>(T t) {
  List<T> list = new List<T>(1);
  list.Add(t);
  return list;
}

(You can write it a bit shorter using shortcuts in newer versions of C#, but still not as short as a yield.)

When the type is a collection, you can cast the reference to the actual type and change the value in the collection:

IEnumerable<int> ienum = Cat<int>(42);

((List<int>)ienum)[0] = 1337;

foreach (int value in ienum) {
  Console.WriteLine(value);
}

will output:

1337

Upvotes: 3

user287107
user287107

Reputation: 9418

this function converts a single item to an enumerable if you have an enumerable, and you want to append one item, for example:

 IEnumerable<someType> Columns;

 var headers = String.Join(",", Columns.Select(c => c.Name).Concat(new string[] { "Last Column" }));

it is nicer to write

 var headers = String.Join(",", Columns.Select(c => c.Name).Concat(Cat("Last Column")));

Upvotes: 0

Reed Copsey
Reed Copsey

Reputation: 564323

This just makes an enumerable type that contains a single element (t). In practical terms, you are correct - it's effectively going to be very similar to just returning a new List<T> with one element, or a new array with one element, etc.

The main difference is that the returned type won't actually be a List<T> or an array - it'll be a compiler generated type. You wouldn't be able to cast the result to a list and add elements, for example. In practical purposes, it'll behave identically to returning a new List<T> as you described.

There is likely no real advantage, other than the developer probably preferred this syntax. I suspect was probably used to allow single elements to work with other portions of the API which expect an IEnumerable<T> to be passed in, though the method name leaves a bit to be desired, IMO.

Upvotes: 5

Related Questions