我在一个开源项目中找到了以下方法:
static IEnumerable<T> Cat<T>(T t) {
yield return t;
}
据我了解,它除了返回IEnumerable<T>
包含t
. 如果我是对的并且它实际上相当于 eg return new List<T>{t};
,那么在这里使用的目的/优势是yield return
什么?如果我错了,我会错过什么?
我在一个开源项目中找到了以下方法:
static IEnumerable<T> Cat<T>(T t) {
yield return t;
}
据我了解,它除了返回IEnumerable<T>
包含t
. 如果我是对的并且它实际上相当于 eg return new List<T>{t};
,那么在这里使用的目的/优势是yield return
什么?如果我错了,我会错过什么?
这只是创建了一个包含单个元素 ( t
) 的可枚举类型。实际上,您是正确的 - 它实际上与仅返回一个List<T>
带有一个元素的新数组或一个带有一个元素的新数组等非常相似。
主要区别在于返回的类型实际上不是 aList<T>
或数组 - 它是编译器生成的类型。例如,您将无法将结果转换为列表并添加元素。List<T>
在实际用途中,它的行为与您所描述的返回一个新的相同。
除了开发人员可能更喜欢这种语法之外,可能没有真正的优势。我怀疑它可能被用来允许单个元素与 API 的其他部分一起工作,这些部分期望IEnumerable<T>
传入一个,尽管方法名称还有一些不足之处,IMO。
返回实际集合和使用之间的区别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
如果您有一个可枚举项,并且您想附加一项,则此函数会将单个项转换为可枚举项,例如:
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")));