使用 yield return 只适用于 IEnumerable<T> 接口吗?

37

当返回类型是IGrouping<TKey, TElement>IDictionary<TKey, TValue>时,我可以使用yield return吗?


可能是一些帮助理解“yield”的问题的重复。 - nawfal
8个回答

52

yield return 适用于以下4种情况:

  • IEnumerable
  • IEnumerable<T>
  • IEnumerator
  • IEnumerator<T>

这是因为它必须在内部构建一个状态机;使用字典等方式不可行。当然,你也可以返回一个适当的类型而不使用 yield return


如果你想要自己实现IEnumerable,这里有一篇非常方便的文章:http://csharpindepth.com/articles/chapter6/iteratorblockimplementation.aspx - Rory
1
@Rory 是的,自己实现会带来很大的麻烦,现在有了迭代器块,我想不出任何“正常”的理由去这样做。虽然我有几个这样的例子,但通常都是为了兼容需要在C#1.2编译器上构建的项目;这可不是“正常”的情况。 - Marc Gravell
虽然在某些情况下IGrouping可能很好用,但使用IEnumerable<Tuple<x,x>>似乎更容易,因此您可以获得yield return的魔力。 - Rory

16

你可以返回 IEnumerable<KeyValuePair<K,V>>,这类似于一个字典。然后你可以使用 yield return 返回 KeyValuePairs。甚至可以在另一个方法中包装它,以创建返回的字典。第一个方法唯一无法保证的是键的唯一性。


11
那么你就会失去 O(1) 的访问时间,必须循环遍历每个 KVP 来找到正确的键,最坏情况下需要 O(n) 的时间。 - Callum Rogers

5
答案:不可以。只有当返回类型为IEnumeratorIEnumerator<T>IEnumerableIEnumerable<T>时,才能使用yield return语句。
来自C# 3.0 spec的§8.14:
在迭代器块(§8.2)中使用yield语句向迭代器或可枚举对象(§10.14.5)中提供一个值,或者表示迭代结束。
来自§10.14.4:
枚举器对象具有以下特征:
1.它实现了IEnumeratorIEnumerator<T>,其中T是迭代器的yield类型。

[...]

来自§10.14.5:

可枚举对象具有以下特征:

  1. 它实现了 IEnumerableIEnumerable<T> 接口,其中 T 是迭代器的 yield 类型。

[...]


2
不行,因为迭代器块只是编译器为您构建的状态机。该功能允许您将项“yield”作为序列的一部分。
如果返回类型不是IEnumerable(例如IDictionary),则编译器将必须生成实现该接口的方法,在那时,这将没有太多意义,因为您将使用集合而不是序列。

2
只需调用迭代器方法并在其后链接ToDictionaryGroupBy,您就可以得到相同的结果。如果需要从多个位置调用它,请将其放入一个单行包装方法中。

1

我不这么认为。虽然文档没有明确说明,但措辞的方式暗示它只能在方法的返回类型为IEnumerableIEnumerable<T>时使用。你可能可以编写一个类来实现IGrouping,给定一个IEnumerable(这将从你的方法中使用yield return返回),但这真的是唯一的选择。


1
语言规范明确指出了它...请参阅ECMA 334中的8.18。 - Marc Gravell

0

您可以始终使用存储库或列表创建IAsyncEnumerable<KeyValuePair<T,V>>,并使用yield return new KeyValuePair<T,V>(obj1,obj2)返回一个新的键值对。然后再编写第二个函数来调用上述方法,该方法返回'IAsyncEnumerable<KeyValuePair<T,V>>',将其添加到字典中,并在if (!dic.TryGetValue(output.Key,out object s))中添加到字典中,假设您想要唯一的键。


-1

不,只是可枚举的 :-)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接