在C#中,使用.NET Framework 4,是否有一种优雅的方法可以重复执行相同的操作一定次数?例如,而不是:
int repeat = 10;
for (int i = 0; i < repeat; i++)
{
Console.WriteLine("Hello World.");
this.DoSomeStuff();
}
我想写一些像:
Action toRepeat = () =>
{
Console.WriteLine("Hello World.");
this.DoSomeStuff();
};
toRepeat.Repeat(10);
或:
Enumerable.Repeat(10, () =>
{
Console.WriteLine("Hello World.");
this.DoSomeStuff();
});
我知道我可以为第一个例子创建我自己的扩展方法,但是不存在已经可以做到这一点的现有功能吗?
答案 0 :(得分:38)
喜欢这个吗?
using System.Linq;
Enumerable.Range(0, 10).ForEach(arg => toRepeat());
这将执行你的方法10次。
<强> [编辑] 强>
我已经习惯在Enumerable上使用ForEach
扩展方法了,我忘了它不是FCL的一部分。
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var item in source)
action(item);
}
如果没有ForEach
扩展方法,您可以执行以下操作:
Enumerable.Range(0, 10).ToList().ForEach(arg => toRepeat());
<强> [编辑] 强>
我认为最优雅的解决方案是实现可重用的方法:
public static void RepeatAction(int repeatCount, Action action)
{
for (int i = 0; i < repeatCount; i++)
action();
}
用法:
RepeatAction(10, () => { Console.WriteLine("Hello World."); });
答案 1 :(得分:23)
没有内置方法可以做到这一点。
原因在于C#试图在语言的功能和命令方面之间进行划分。 C#只有在不产生副作用时才能轻松进行函数式编程。因此,您可以获得LINQ的Where
,Select
等集合处理方法,但you do not get ForEach
。 1
以类似的方式,你在这里尝试做的是找到一些表达本质上是命令行动的功能性方法。尽管C#为您提供了执行此操作的工具,但它并不会让您感觉轻松,因为这样做会使您的代码不清晰且不具有惯用性。
1 有List<T>.ForEach
,但不是IEnumerable<T>.ForEach
。我会说List<T>.ForEach
的存在是一个历史的神器,源于框架设计者在.NET 2.0时代没有考虑过这些问题;只有在3.0中才能明确划分明确的分工。
答案 2 :(得分:9)
为了简化一个班轮你可以做到这一点。不确定你的想法...
Enumerable.Repeat<Action>(() =>
{
Console.WriteLine("Hello World.");
this.DoSomeStuff();
}, 10).ToList().ForEach(x => x());
答案 3 :(得分:7)
如果不推出自己的扩展程序,我猜你可以做这样的事情
Action toRepeat = () => {
Console.WriteLine("Hello World.");
this.DoSomeStuff();
};
int repeat = 10;
Enumerable.Range(0, repeat).ToList().ForEach(i => toRepeat());
答案 4 :(得分:6)
Enumerable.Repeat<Action>(() => { Console.WriteLine("Hello World"); this.DoSomething(); },10).ToList().ForEach(f => f.Invoke());
优雅不是吗?
答案 5 :(得分:1)
Table table = frame.AddTable();
int columnsCount = 7;
Enumerable.Repeat<Func<Column>>(table.AddColumn, columnsCount)
.ToList()
.ForEach(addColumn => addColumn());
//or
Enumerable.Range(0, columnsCount)
.ToList()
.ForEach(iteration => table.AddColumn());
由于ToList(),这些选项并不优雅,但两者都适用于我的情况
答案 6 :(得分:1)
声明扩展名:
public static void Repeat(this Action action, int times){
while (times-- > 0)
action.Invoke();
}
您可以将扩展方法用作:
new Action(() =>
{
Console.WriteLine("Hello World.");
this.DoSomeStuff();
}).Repeat(10);
答案 7 :(得分:0)
我将其编写为Int32
扩展方法。起初,我认为这听起来似乎不是一个好主意,但是当您使用它时,它似乎真的很棒。
public static void Repeat(
this int count,
Action action
) {
for (int x = 0; x < count; x += 1)
action();
}
用法:
5.Repeat(DoThing);
value.Repeat(() => queue.Enqueue(someItem));
(value1 - value2).Repeat(() => {
// complex implementation
});
请注意,它将对值<= 0
不执行任何操作。起初,我打算抛出负数,但是当比较两个数时,我总是必须检查哪个数字更大。如果差异为正,则可以使差异起作用,否则不进行任何操作。
如果您想不考虑符号而重复,则可以编写一个Abs
扩展方法(value.Abs().Repeat(() => { });
或-5.RepeatAbs(() => { });
),然后两个数字之差的顺序无关紧要
其他变体也是可能的,例如传递索引或投影到类似于Select
的值。
我知道这里有Enumerable.Range
,但是更加简洁。
答案 8 :(得分:0)
我发现最方便的是:
Enumerable.Range(0, 10).Select(_ => action());
答案 9 :(得分:0)
如果您的操作是线程安全的,您可以使用
Parallel.For(0, 10, i => myAction(schema));