我想编写一个扩展方法(以流利的语法使用它),以便如果序列是:
List< int> lst = new List< int>(){1,2,3 };
我想重复3次(例如)。所以输出将是123123123
我写了这个:
public static IEnumerable<TSource> MyRepeat<TSource>(this IEnumerable<TSource> source,int n)
{
return Enumerable.Repeat(source,n).SelectMany(f=>f);
}
现在我可以这样做:
lst.MyRepeat(3)
输出:
问题:
我不应该在扩展方法中使用Yield吗?我试过yield return
,但它不在这里工作。为什么这样,我应该使用它。
在Ant回答之后我将其改为:
public static IEnumerable<TSource> MyRepeat<TSource>(this IEnumerable<TSource> source,int n)
{
var k=Enumerable.Repeat(source,n).SelectMany(f=>f);
foreach (var element in k)
{
yield return element;
}
}
但是有什么不同吗?
答案 0 :(得分:3)
这是因为以下已经返回一个IEnumerable:
Enumerable.Repeat(source,n).SelectMany(f=>f);
当您使用yield
关键字时,您指定对该方法的给定迭代将返回以下内容。所以你实际上是在说“每次迭代都会产生IEnumerable<TSource>
”,实际上,对返回IEnumerable<TSource>
的方法的每次迭代都应该产生TSource
。
因此,您的错误 - 当您对MyRepeat
进行迭代时,您需要返回TSource
,但由于您正在尝试yield
IEnumerable
, em>实际上尝试从每次迭代返回IEnumerable
而不是返回单个元素。
您的编辑应该有效,但有点无意义 - 如果您只是直接返回IEnumerable,则在迭代它(或调用ToList
或其他内容)之前不会枚举它。在您的第一个示例中,SelectMany
(或其嵌套方法之一)已经使用yield
,这意味着yield
已经存在,它只是隐含在您的方法中。
答案 1 :(得分:2)
Ant P的答案当然是正确的。
如果要构建自己返回的枚举,而不是依赖于SelectMany,则可以使用yield。例如:
public static IEnumerable<T> Repeat<T>(this IEnumberable<T> items, int repeat)
{
for (int i = 0; i < repeat; ++i)
foreach(T item in items)
yield return item;
}
你产生的东西是序列的元素。代码是生成生成元素序列的指令。