3

我在一个开源项目中找到了以下方法:

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

据我了解,它除了返回IEnumerable<T>包含t. 如果我是对的并且它实际上相当于 eg return new List<T>{t};,那么在这里使用的目的/优势是yield return什么?如果我错了,我会错过什么?

完整的源代码可以在这里找到

4

3 回答 3

5

这只是创建了一个包含单个元素 ( t) 的可枚举类型。实际上,您是正确的 - 它实际上与仅返回一个List<T>带有一个元素的新数组或一个带有一个元素的新数组等非常相似。

主要区别在于返回的类型实际上不是 aList<T>或数组 - 它是编译器生成的类型。例如,您将无法将结果转换为列表并添加元素。List<T>在实际用途中,它的行为与您所描述的返回一个新的相同。

除了开发人员可能更喜欢这种语法之外,可能没有真正的优势。我怀疑它可能被用来允许单个元素与 API 的其他部分一起工作,这些部分期望IEnumerable<T>传入一个,尽管方法名称还有一些不足之处,IMO。

于 2012-09-24T18:52:40.743 回答
3

返回实际集合和使用之间的区别yield只是您返回的对象的类型。

如果您返回任何实现的集合,IEnumerable<T>则返回的对象的实际类型将是该类型。例如,如果您返回 a List<T>,则返回的引用将是类型IEnumerable<T>,但引用指向的对象的实际类型是 的实例List<T>

如果使用yield,编译器将创建一个没有已知名称的枚举器对象。返回的引用类型也将是IEnumerable<T>,但引用指向的对象的实际类型将是编译器创建的东西。

例如获取为整数创建的枚举器类型的名称:

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

将显示编译器使用的内部名称,例如我从代码中得到的这个结果:

<Cat>d__5`1

如果函数将返回 a List<int>,则类型将显示为:

List`1

让编译器为此创建枚举器的动机可能只是它比这样的更短:

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

(您可以使用较新版本的 C# 中的快捷方式将其写得更短一些,但仍不如yield.)

当类型是集合时,您可以将引用转换为实际类型并更改集合中的值:

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

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

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

将输出:

1337
于 2012-09-24T18:58:47.917 回答
0

如果您有一个可枚举项,并且您想附加一项,则此函数会将单个项转换为可枚举项,例如:

 IEnumerable<someType> Columns;

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

写起来更好

 var headers = String.Join(",", Columns.Select(c => c.Name).Concat(Cat("Last Column")));
于 2012-09-24T18:55:39.930 回答