如何用 C# 中的函数语句替换 for 循环?

发布于 2024-08-28 20:31:48 字数 319 浏览 9 评论 0原文

一位同事曾经说过,每次我写一个 for 循环时,上帝都在杀死一只小猫。

当被问及如何避免 for 循环时,他的答案是使用函数式语言。但是,如果您陷入非函数式语言(例如 C#)的困境,有哪些技术可以避免 for 循环或通过重构消除它们?也许使用 lambda 表达式和 LINQ?如果是这样,怎么办?

问题

所以问题归结为:

  1. 为什么 for 循环不好?或者,在什么情况下需要避免 for 循环以及为什么?
  2. 您能否提供 C# 代码示例来说明它之前(即使用循环)和之后不使用循环的情况?

A colleague once said that God is killing a kitten every time I write a for-loop.

When asked how to avoid for-loops, his answer was to use a functional language. However, if you are stuck with a non-functional language, say C#, what techniques are there to avoid for-loops or to get rid of them by refactoring? With lambda expressions and LINQ perhaps? If so, how?

Questions

So the question boils down to:

  1. Why are for-loops bad? Or, in what context are for-loops to avoid and why?
  2. Can you provide C# code examples of how it looks before, i.e. with a loop, and afterwards without a loop?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

落花浅忆 2024-09-04 20:31:49

当您操作某些数据集并想要转换、过滤或聚合元素时,函数构造通常比 for 循环更清楚地表达您的意图。

当您想要重复执行某些操作时,循环非常合适。


例如,比

int x = array.Sum();

以下更清楚地表达您的意图

int x = 0;
for (int i = 0; i < array.Length; i++)
{
    x += array[i];
}

Functional constructs often express your intent more clearly than for-loops in cases where you operate on some data set and want to transform, filter or aggregate the elements.

Loops are very appropriate when you want to repeatedly execute some action.


For example

int x = array.Sum();

much more clearly expresses your intent than

int x = 0;
for (int i = 0; i < array.Length; i++)
{
    x += array[i];
}
话少心凉 2024-09-04 20:31:49

为什么 for 循环不好?或者说,在什么情况下
上下文是要避免的 for 循环
为什么?

如果您的同事有函数式编程,那么他可能已经熟悉避免 for 循环的基本原因:

折叠/映射/过滤涵盖了列表遍历的大多数用例,并且非常适合函数组合。 For 循环不是一个好的模式,因为它们不可组合。

大多数时候,您会遍历列表来折叠(聚合)、映射或过滤列表中的值。这些高阶函数已经存在于每种主流函数式语言中,因此您很少看到函数式代码中使用 for 循环习惯用法。

高阶函数是函数组合的基础,这意味着您可以轻松地将简单的函数组合成更复杂的函数。

举一个重要的例子,请考虑命令式语言中的以下内容:

let x = someList;
y = []
for x' in x
    y.Add(f x')

z = []
for y' in y
    z.Add(g y')

在函数式语言中,我们会编写 map g (map fx),或者我们可以使用 消除中间列表地图(f.g)x。现在,原则上我们可以从命令式版本中消除中间列表,这会有所帮助,但效果不大。

命令式版本的主要问题在于 for 循环是实现细节。如果你想改变这个函数,你就改变它的实现——最终你会修改很多代码。

举个例子,您将如何强制编写 map g (filter fx) ?好吧,由于您无法重用原始的映射和映射代码,因此您需要编写一个新的函数来进行过滤和映射。如果你有 50 种映射方式和 50 种过滤方式,你如何需要 50^50 个函数,或者你需要使用命令模式模拟将函数作为第一类参数传递的能力(如果你曾经尝试过函数式编程)在 Java 中,你就会明白这将是一场多么可怕的噩梦)。

回到功能宇宙,您可以概括 map g (map fx),让您可以用 filterfilter 替换 map code>fold 根据需要:

let apply2 a g b f x = a g (b f x)

并使用 apply2 map g filter fapply2 map g map fapply2 filter g filter f 调用它代码> 或任何你需要的东西。现在,您可能永远不会在现实世界中编写这样的代码,您可能会使用以下方法来简化它:

let mapmap g f = apply2 map g map f
let mapfilter g f = apply2 map g filter f

高阶函数和函数组合为您提供了命令式代码无法获得的抽象级别。

抽象出循环的实现细节可以让您无缝地将一个循环替换为另一个循环。

请记住,for 循环是一种实现细节。如果需要更改实现,则需要更改每个 for 循环。

映射/折叠/过滤抽象掉循环。因此,如果您想更改循环的实现,可以在这些函数中更改它。

现在您可能想知道为什么要抽象出循环。考虑将项目从一种类型映射到另一种类型的任务:通常,项目一次映射一个,顺序且独立于所有其他项目。大多数时候,像这样的映射是并行化的主要候选者。

不幸的是,顺序映射和并行映射的实现细节不可互换。如果您的代码中有大量顺序映射,并且希望将它们替换为并行映射,那么您有两种选择:在代码库中复制/粘贴相同的并行映射代码,或者将映射逻辑抽象为两个函数mappmap。一旦你选择了第二条路,你就已经深入函数式编程领域了。

如果您了解函数组合的目的并抽象出实现细节(甚至像循环这样琐碎的细节),您就可以开始理解函数式编程如何以及为何如此强大。

Why are for-loops bad? Or, in what
context are for-loops to avoid and
why?

If your colleague has a functional programming, then he's probably already familiar with the basic reasons for avoiding for loops:

Fold / Map / Filter cover most use cases of list traversal, and lend themselves well to function composition. For-loops aren't a good pattern because they aren't composable.

Most of the time, you traverse through a list to fold (aggregate), map, or filter values in a list. These higher order functions already exist in every mainstream functional language, so you rarely see the for-loop idiom used in functional code.

Higher order functions are the bread and butter of function composition, meaning you can easily combine simple function into something more complex.

To give a non-trivial example, consider the following in an imperative language:

let x = someList;
y = []
for x' in x
    y.Add(f x')

z = []
for y' in y
    z.Add(g y')

In a functional language, we'd write map g (map f x), or we can eliminate the intermediate list using map (f . g) x. Now we can, in principle, eliminate the intermediate list from the imperative version, and that would help a little -- but not much.

The main problem with the imperative version is simply that the for-loops are implementation details. If you want change the function, you change its implementation -- and you end up modifying a lot of code.

Case in point, how would you write map g (filter f x) in imperatively? Well, since you can't reuse your original code which maps and maps, you need to write a new function which filters and maps instead. And if you have 50 ways to map and 50 ways to filter, how you need 50^50 functions, or you need to simulate the ability to pass functions as first-class parameters using the command pattern (if you've ever tried functional programming in Java, you understand what a nightmare this can be).

Back in the the functional universe, you can generalize map g (map f x) in way that lets you swap out the map with filter or fold as needed:

let apply2 a g b f x = a g (b f x)

And call it using apply2 map g filter f or apply2 map g map f or apply2 filter g filter f or whatever you need. Now you'd probably never write code like that in the real world, you'd probably simplify it using:

let mapmap g f = apply2 map g map f
let mapfilter g f = apply2 map g filter f

Higher-order functions and function composition give you a level of abstraction that you cannot get with the imperative code.

Abstracting out the implementation details of loops let's you seamlessly swap one loop for another.

Remember, for-loops are an implementation detail. If you need to change the implementation, you need to change every for-loop.

Map / fold / filter abstract away the loop. So if you want to change the implementation of your loops, you change it in those functions.

Now you might wonder why you'd want to abstract away a loop. Consider the task of mapping items from one type to another: usually, items are mapped one at a time, sequentially, and independently from all other items. Most of the time, maps like this are prime candidates for parallelization.

Unfortunately, the implementation details for sequential maps and parallel maps aren't interchangeable. If you have a ton of sequential maps all over your code, and you want swap them out for parallel maps, you have two choices: copy/paste the same parallel mapping code all over your code base, or abstract away mapping logic into two functions map and pmap. Once you're go the second route, you're already knee-deep in functional programming territory.

If you understand the purpose of function composition and abstracting away implementation details (even details as trivial as looping), you can start to appreciate just how and why functional programming is so powerful in the first place.

少女净妖师 2024-09-04 20:31:49
  1. For 循环还不错。保留 for 循环有很多非常充分的理由。
  2. 您通常可以通过在 C# 中使用 LINQ 重新设计 for 循环来“避免”for 循环,LINQ 提供了更具声明性的语法。根据具体情况,这可能是好是坏:

比较以下内容:

var collection = GetMyCollection();
for(int i=0;i<collection.Count;++i)
{
     if(collection[i].MyValue == someValue)
          return collection[i];
}

与 foreach:

var collection = GetMyCollection();
foreach(var item in collection)
{
     if(item.MyValue == someValue)
          return item;
}

与 LINQ: 就

var collection = GetMyCollection();
return collection.FirstOrDefault(item => item.MyValue == someValue);

我个人而言,所有三个选项都有自己的位置,我都使用它们。这是使用最适合您的场景的选项的问题。

  1. For loops are not bad. There are many very valid reasons to keep a for loop.
  2. You can often "avoid" a for loop by reworking it using LINQ in C#, which provides a more declarative syntax. This can be good or bad depending on the situation:

Compare the following:

var collection = GetMyCollection();
for(int i=0;i<collection.Count;++i)
{
     if(collection[i].MyValue == someValue)
          return collection[i];
}

vs foreach:

var collection = GetMyCollection();
foreach(var item in collection)
{
     if(item.MyValue == someValue)
          return item;
}

vs. LINQ:

var collection = GetMyCollection();
return collection.FirstOrDefault(item => item.MyValue == someValue);

Personally, all three options have their place, and I use them all. It's a matter of using the most appropriate option for your scenario.

嗫嚅 2024-09-04 20:31:49

for 循环没有任何问题,但以下是人们可能更喜欢函数式/声明式方法(如 LINQ)的一些原因,在这种方法中,您可以声明您想要的内容,而不是如何获得它:-

  1. 函数式方法可能更容易使用 PLINQ 手动并行化或由编译器。随着 CPU 转向更多内核,这可能会变得更加重要。

  2. 函数式方法可以更轻松地在多步骤过程中实现延迟求值,因为您可以将中间结果作为尚未完全求值的简单变量传递到下一步,而不是完全求值第一步然后传递下一步的集合(或者不使用单独的方法和yield语句来实现相同的程序)。

  3. 函数式方法通常更短且更易于阅读。

  4. 函数式方法通常会消除 for 循环中的复杂条件体(例如 if 语句和“继续”语句),因为您可以将 for 循环分解为逻辑步骤 - 选择所有匹配的元素,对它们执行操作,.. .

There's nothing wrong with for loops but here are some of the reasons people might prefer functional/declarative approaches like LINQ where you declare what you want rather than how you get it:-

  1. Functional approaches are potentially easier to parallelize either manually using PLINQ or by the compiler. As CPUs move to even more cores this may become more important.

  2. Functional approaches make it easier to achieve lazy evaluation in multi-step processes because you can pass the intermediate results to the next step as a simple variable which hasn't been evaluated fully yet rather than evaluating the first step entirely and then passing a collection to the next step (or without using a separate method and a yield statement to achieve the same procedurally).

  3. Functional approaches are often shorter and easier to read.

  4. Functional approaches often eliminate complex conditional bodies within for loops (e.g. if statements and 'continue' statements) because you can break the for loop down into logical steps - selecting all the elements that match, doing an operation on them, ...

怎言笑 2024-09-04 20:31:49

For 循环不会杀人(或小猫、小狗或小东西)。人们杀人。
For 循环本身并不坏。然而,就像其他事情一样,使用它们的方式可能会很糟糕。

For loops don't kill people (or kittens, or puppies, or tribbles). People kill people.
For loops, in and of themselves, are not bad. However, like anything else, it's how you use them that can be bad.

时光礼记 2024-09-04 20:31:49

有时你不只杀死一只小猫。

for (int i = 0; i < kittens.Length; i++)
{
小猫[i].Kill();
}

你会把他们都杀掉。

Sometime you don't kill just one kitten.

for (int i = 0; i < kittens.Length; i++)
{
kittens[i].Kill();
}

Sometimes you kill them all.

绝影如岚 2024-09-04 20:31:49

您可以充分重构代码,这样您就不会经常看到它们。一个好的函数名肯定比 for 循环更具可读性。

以 AndyC 中的示例:

Loop

// mystrings is a string array
List<string> myList = new List<string>();
foreach(string s in mystrings)
{
    if(s.Length > 5)
    {
        myList.add(s);
    }
}

Linq

// mystrings is a string array
List<string> myList = mystrings.Where<string>(t => t.Length > 5)
                               .ToList<string();

无论您在函数中使用第一个还是第二个版本,它都更容易阅读

var filteredList = myList.GetStringLongerThan(5);

现在这是一个过于简单的示例,但您明白我的意思。

You can refactor your code well enough so that you won't see them often. A good function name is definitely more readable that a for loop.

Taking the example from AndyC :

Loop

// mystrings is a string array
List<string> myList = new List<string>();
foreach(string s in mystrings)
{
    if(s.Length > 5)
    {
        myList.add(s);
    }
}

Linq

// mystrings is a string array
List<string> myList = mystrings.Where<string>(t => t.Length > 5)
                               .ToList<string();

Wheter you use the first or the second version inside your function, It's easier to read

var filteredList = myList.GetStringLongerThan(5);

Now that's an overly simple example, but you get my point.

苍白女子 2024-09-04 20:31:49

你同事的说法不对。 For 循环本身并不坏。它们干净、可读并且不太容易出错。

Your colleague is not right. For loops are not bad per se. They are clean, readable and not particularly error prone.

¢好甜 2024-09-04 20:31:49

你的同事关于 for 循环在所有情况下都很糟糕的观点是错误的,但正确的是它们可以在功能上重写。

假设您有一个如下所示的扩展方法:

void ForEach<T>(this IEnumerable<T> collection, Action <T> action)
{
    foreach(T item in collection)
    {
        action(item)
    }
}

然后您可以编写一个如下所示的循环:

mycollection.ForEach(x => x.DoStuff());

这现在可能不是很有用。但是,如果您随后将 ForEach 扩展方法的实现替换为使用多线程方法,那么您将获得并行性的优势。

这显然并不总是有效,这种实现仅在循环迭代完全相互独立时才有效,但它可能很有用。

另外:永远要警惕那些说某些编程结构总是错误的人。

Your colleague is wrong about for loops being bad in all cases, but correct that they can be rewritten functionally.

Say you have an extension method that looks like this:

void ForEach<T>(this IEnumerable<T> collection, Action <T> action)
{
    foreach(T item in collection)
    {
        action(item)
    }
}

Then you can write a loop like this:

mycollection.ForEach(x => x.DoStuff());

This may not be very useful now. But if you then replace your implementation of the ForEach extension method for use a multi threaded approach then you gain the advantages of parallelism.

This obviously isn't always going to work, this implementation only works if the loop iterations are completely independent of each other, but it can be useful.

Also: always be wary of people who say some programming construct is always wrong.

陪你搞怪i 2024-09-04 20:31:49

一个简单的(实际上毫无意义的)示例:

Loop

// mystrings is a string array
List<string> myList = new List<string>();
foreach(string s in mystrings)
{
    if(s.Length > 5)
    {
        myList.add(s);
    }
}

Linq

// mystrings is a string array
List<string> myList = mystrings.Where<string>(t => t.Length > 5).ToList<string>();

在我的书中,第二个看起来更整洁和简单,尽管第一个没有任何问题。

A simple (and pointless really) example:

Loop

// mystrings is a string array
List<string> myList = new List<string>();
foreach(string s in mystrings)
{
    if(s.Length > 5)
    {
        myList.add(s);
    }
}

Linq

// mystrings is a string array
List<string> myList = mystrings.Where<string>(t => t.Length > 5).ToList<string>();

In my book, the second one looks a lot tidier and simpler, though there's nothing wrong with the first one.

伴我心暖 2024-09-04 20:31:49

有时,如果存在更有效的替代方案,则 for 循环会很糟糕。例如搜索,对列表进行排序然后使用快速排序或二进制排序可能会更有效。或者当您迭代数据库中的项目时。在数据库中使用基于集合的操作通常比迭代项目更有效。

否则,如果 for 循环,尤其是 for-each 最有意义并且可读,那么我会选择它,而不是将其分解为不那么直观的东西。我个人不相信这些听起来很宗教的“总是这样做,因为这是唯一的方法”。相反,最好有指导方针,并了解在什么情况下适合应用这些指导方针。你问“为什么”是件好事!

Sometimes a for-loop is bad if there exists a more efficient alternative. Such as searching, where it might be more efficient to sort a list and then use quicksort or binary sort. Or when you are iterating over items in a database. It is usually much more efficient to use set-based operations in a database instead of iterating over the items.

Otherwise if the for-loop, especially a for-each makes the most sense and is readable, then I would go with that rather than rafactor it into something that isn't as intuitive. I personally don't believe in these religious sounding "always do it this way, because that is the only way". Rather it is better to have guidelines, and understand in what scenarios it is appropriate to apply those guidelines. It is good that you ask the Why's!

佼人 2024-09-04 20:31:49

可以说,For 循环是“糟糕的”,因为它意味着 CPU 中的分支预测,并且当分支预测失败时,性能可能会下降。

但是 CPU(分支预测准确度为 97%)和具有循环展开等技术的编译器,使得循环性能的降低可以忽略不计。

For loop is, let's say, "bad" as it implies branch prediction in CPU, and possibly performance decrease when branch prediction miss.

But CPU (having a branch prediction accuracy of 97%) and compiler with tecniques like loop unrolling, make loop performance reduction negligible.

茶色山野 2024-09-04 20:31:49

如果直接抽象 for 循环,您会得到:

void For<T>(T initial, Func<T,bool> whilePredicate, Func<T,T> step, Action<T> action)
{
    for (T t = initial; whilePredicate(t); step(t))
    {
        action(t);
    }
}

从函数式编程的角度来看,我遇到的问题是 void 返回类型。它本质上意味着 for 循环不能很好地与任何东西组合。因此,我们的目标不是从 for 循环到某个函数的 1-1 转换,而是从功能角度思考并避免做不组合的事情。不要考虑循环和行动,而是考虑整个问题以及您要映射的内容和映射到的内容。

If you abstract the for loop directly you get:

void For<T>(T initial, Func<T,bool> whilePredicate, Func<T,T> step, Action<T> action)
{
    for (T t = initial; whilePredicate(t); step(t))
    {
        action(t);
    }
}

The problem I have with this from a functional programming perspective is the void return type. It essentially means that for loops do not compose nicely with anything. So the goal is not to have a 1-1 conversion from for loop to some function, it is to think functionally and avoid doing things that do not compose. Instead of thinking of looping and acting think of the whole problem and what you are mapping from and to.

小伙你站住 2024-09-04 20:31:49

for 循环始终可以替换为不涉及使用循环的递归函数。递归函数是一种更具功能性的编程方式。

但如果你盲目地用递归函数代替 for 循环,那么小猫和小狗都会死亡数以百万计,你也会被迅猛龙杀死。

好的,这是一个例子。但请记住,我不主张进行此更改!

for 循环

for (int index = 0; index < args.Length; ++index)
    Console.WriteLine(args[index]);

可以更改为递归函数调用

WriteValuesToTheConsole(args, 0);


static void WriteValuesToTheConsole<T>(T[] values, int startingIndex)
{
    if (startingIndex < values.Length)
    {
        Console.WriteLine(values[startingIndex]);
        WriteValuesToTheConsole<T>(values, startingIndex + 1);
    }
}

这对于大多数值来说应该是一样的,但它不太清晰,效率较低,并且如果数组太大,可能会耗尽堆栈。

A for loop can always be replaced by a recursive function that doesn't involve the use of a loop. A recursive function is a more functional stye of programming.

But if you blindly replace for loops with recursive functions, then kittens and puppies will both die by the millions, and you will be done in by a velocirapter.

OK, here's an example. But please keep in mind that I do not advocate making this change!

The for loop

for (int index = 0; index < args.Length; ++index)
    Console.WriteLine(args[index]);

Can be changed to this recursive function call

WriteValuesToTheConsole(args, 0);


static void WriteValuesToTheConsole<T>(T[] values, int startingIndex)
{
    if (startingIndex < values.Length)
    {
        Console.WriteLine(values[startingIndex]);
        WriteValuesToTheConsole<T>(values, startingIndex + 1);
    }
}

This should work just the same for most values, but it is far less clear, less effecient, and could exhaust the stack if the array is too large.

自此以后,行同陌路 2024-09-04 20:31:49

您的同事可能会建议,在涉及数据库数据的某些情况下,最好在查询时使用聚合 SQL 函数,例如 Average() 或 Sum(),而不是在 ADO .NET 中在 C# 端处理数据。应用。

否则,如果使用得当,for 循环会非常有效,但要意识到,如果您发现自己将它们嵌套到三个或更多顺序,则可能需要一种更好的算法,例如涉及递归、子例程或两者的算法。例如,冒泡排序在最坏情况(逆序)情况下的运行时间为 O(n^2),但递归排序算法仅为 O(n log n),这要好得多。

希望这有帮助。

  • 吉姆

Your colleague may be suggesting under certain circumstances where database data is involved that it is better to use an aggregate SQL function such as Average() or Sum() at query time as opposed to processing the data on the C# side within an ADO .NET application.

Otherwise for loops are highly effective when used properly, but realize that if you find yourself nesting them to three or more orders, you might need a better algorithm, such as one that involves recursion, subroutines or both. For example, a bubble sort has a O(n^2) runtime on its worst-case (reverse order) scenario, but a recursive sort algorithm is only O(n log n), which is much better.

Hopefully this helps.

  • Jim
执笏见 2024-09-04 20:31:49

任何语言中的任何构造都是有原因的。它是用来完成任务的工具。意味着结束。在每种情况下,都有适当使用它的方式,即以清晰简洁的方式并在语言的精神范围内和滥用它的方式。这适用于严重错位的 goto 语句以及 for 循环难题,以及 whiledo-whileswitch/caseif-then-else 等。如果 for 循环是适合您的工具在做时,使用它,你的同事将需要接受你的设计决策。

Any construct in any language is there for a reason. It's a tool to be used to accomplish a task. Means to an end. In every case, there are manners in which to use it appropriately, that is, in a clear and concise way and within the spirit of the language AND manners to abuse it. This applies to the much-misaligned goto statement as well as to your for loop conundrum, as well as while, do-while, switch/case, if-then-else, etc. If the for loop is the right tool for what you're doing, USE IT and your colleague will need to come to terms with your design decision.

春夜浅 2024-09-04 20:31:49

这取决于循环中的内容,但他/她可能指的是递归函数

    //this is the recursive function
    public static void getDirsFiles(DirectoryInfo d)
    {
        //create an array of files using FileInfo object
        FileInfo [] files;
        //get all files for the current directory
        files = d.GetFiles("*.*");

        //iterate through the directory and print the files
        foreach (FileInfo file in files)
        {
            //get details of each file using file object
            String fileName = file.FullName;
            String fileSize = file.Length.ToString();
            String fileExtension =file.Extension;
            String fileCreated = file.LastWriteTime.ToString();

            io.WriteLine(fileName + " " + fileSize + 
               " " + fileExtension + " " + fileCreated);
        }

        //get sub-folders for the current directory
        DirectoryInfo [] dirs = d.GetDirectories("*.*");

        //This is the code that calls 
        //the getDirsFiles (calls itself recursively)
        //This is also the stopping point 
        //(End Condition) for this recursion function 
        //as it loops through until 
        //reaches the child folder and then stops.
        foreach (DirectoryInfo dir in dirs)
        {
            io.WriteLine("--------->> {0} ", dir.Name);
            getDirsFiles(dir);
        }

    }

It depends upon what is in the loop but he/she may be referring to a recursive function

    //this is the recursive function
    public static void getDirsFiles(DirectoryInfo d)
    {
        //create an array of files using FileInfo object
        FileInfo [] files;
        //get all files for the current directory
        files = d.GetFiles("*.*");

        //iterate through the directory and print the files
        foreach (FileInfo file in files)
        {
            //get details of each file using file object
            String fileName = file.FullName;
            String fileSize = file.Length.ToString();
            String fileExtension =file.Extension;
            String fileCreated = file.LastWriteTime.ToString();

            io.WriteLine(fileName + " " + fileSize + 
               " " + fileExtension + " " + fileCreated);
        }

        //get sub-folders for the current directory
        DirectoryInfo [] dirs = d.GetDirectories("*.*");

        //This is the code that calls 
        //the getDirsFiles (calls itself recursively)
        //This is also the stopping point 
        //(End Condition) for this recursion function 
        //as it loops through until 
        //reaches the child folder and then stops.
        foreach (DirectoryInfo dir in dirs)
        {
            io.WriteLine("--------->> {0} ", dir.Name);
            getDirsFiles(dir);
        }

    }
梨涡 2024-09-04 20:31:49

问题是循环是否会改变状态或引起副作用。如果是这样,请使用 foreach 循环。如果没有,请考虑使用 LINQ 或其他函数结构。

请参阅“foreach”与“ForEach” 在 Eric Lippert 的博客上。

The question is if the loop will be mutating state or causing side effects. If so, use a foreach loop. If not, consider using LINQ or other functional constructs.

See "foreach" vs "ForEach" on Eric Lippert's Blog.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文