处理“循环初始化”的其他方式包括:在C#中 [英] Other ways to deal with "loop initialization" in C#

查看:78
本文介绍了处理“循环初始化”的其他方式包括:在C#中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我要说的是,我同意goto语句在很大程度上不受现代编程语言中更高级别的构造的影响,并且在有合适的替代方法时不应该使用。

To start with I'll say that I agree that goto statements are largely made irrelevant by higher level constructs in modern programming languages and shouldn't be used when a suitable substitute is available.

我最近重新阅读了史蒂夫·麦康奈尔(Steve McConnell)的《代码完成》(Code Complete)的原始版本,却忘记了他对常见编码问题的建议。几年前刚开始阅读时,我就读过它,但没想到我意识到该食谱有多有用。编码问题如下:在执行循环时,您通常需要执行循环的一部分以初始化状态,然后使用其他逻辑执行循环,并以相同的初始化逻辑结束每个循环。一个具体的示例是实现String.Join(delimiter,array)方法。

I was re-reading an original edition of Steve McConnell's Code Complete recently and had forgotten about his suggestion for a common coding problem. I had read it years ago when I was first getting started and don't think I realized how useful the recipe would be. The coding problem is the following: when executing a loop you often need to execute part of the loop to initialize state and then execute the loop with some other logic and ending each loop with the same initialization logic. A concrete example is implementing String.Join(delimiter, array) method.

我认为每个人首先要解决的问题就是这个。假设已定义append方法,以将参数添加到返回值中。

I think everybody's first take on the problem is this. Assume the append method is defined to add the argument to your return value.

bool isFirst = true;
foreach (var element in array)
{
  if (!isFirst)
  {
     append(delimiter);
  }
  else
  {
    isFirst = false;
  }

  append(element);
}

注意:对此的略微优化是删除else并将其放在循环结束。分配通常是一条指令,等效于else指令,并且将基本块的数量减少1,并增加主要部分的基本块大小。结果是在每个循环中执行一个条件以确定是否应添加定界符。

Note: A slight optimization to this is to remove the else and put it at the end of the loop. An assignment usually being a single instruction and equivalent to an else and decreases the number of basic blocks by 1 and increases the basic block size of the main part. The result being that execute a condition in each loop to determine if you should add the delimiter or not.

我也已经看到并使用了其他方法来处理此常见问题循环问题。您可以先在循环外部执行初始元素代码,然后从第二个元素到最后执行循环。您还可以更改逻辑,使其始终添加元素,然后再添加定界符,循环完成后,您只需删除最后添加的定界符即可。

I've also seen and used other takes on dealing with this common loop problem. You can execute the initial element code first outside the loop, then perform your loop from the second element to the end. You can also change the logic to always append the element then the delimiter and once the loop is completed you can simply remove the last delimiter you added.

后一种解决方案倾向于成为我更喜欢的代码是因为它不重复任何代码。如果初始化顺序的逻辑发生了变化,则无需记住在两个位置进行修复。但是,它确实需要额外的工作才能执行某些操作然后将其撤消,这至少会导致额外的cpu周期,并且在许多情况下(例如我们的String.Join示例)也需要额外的内存。

The latter solution tends to be the one that I prefer only because it doesn't duplicate any code. If the logic of the initialization sequence ever changes, you don't have to remember to fix it in two places. It does however require extra "work" to do something and then undo it, causing at least extra cpu cycles and in many cases such as our String.Join example requires extra memory as well.

然后我很高兴阅读这个构造

I was excited then to read this construct

var enumerator = array.GetEnumerator();
if (enumerator.MoveNext())
{
  goto start;
  do {
    append(delimiter);

  start:
    append(enumerator.Current);
  } while (enumerator.MoveNext());
}

这里的好处是您没有重复的代码,也没有其他工作。您将在执行第一个循环的一半时开始循环,这就是您的初始化。您只能使用do while构造来模拟其他循环,但翻译起来容易,阅读起来并不困难。

The benefit here being that you get no duplicated code and you get no additional work. You start your loop half way into the execution of your first loop and that is your initialization. You are limited to simulating other loops with the do while construct but the translation is easy and reading it is not difficult.

所以,现在是问题了。我很乐意尝试将其添加到我正在处理的某些代码中,但发现它不起作用。在C,C ++,Basic中效果很好,但事实证明,在C#中,您无法跳转到不是父范围的其他词法范围内的标签。我感到非常失望。所以我不禁要问,在C#中解决这个非常常见的编码问题(我主要在字符串生成中)的最佳方法是什么?

So, now the question. I happily went to try adding this to some code I was working on and found it didn't work. Works great in C, C++, Basic but it turns out in C# you can't jump to a label inside a different lexical scope that is not a parent scope. I was very disappointed. So I was left wondering, what is the best way to deal with this very common coding problem (I see it mostly in string generation) in C#?

也许更多具体要求如下:

To perhaps be more specific with requirements:


  • 不要重复代码

  • 不要做不必要的工作

  • 不要比其他代码慢2到3倍

  • 易读

  • Don't duplicate code
  • Don't do unnecessary work
  • Don't be more than 2 or 3 times slower than other code
  • Be readable

我认为可读性是我说过的唯一可能会受苦的东西。但是,它在C#中不起作用,所以下一个最好的是什么?

I think readability is the only thing that might arguably suffer with the recipe I stated. However it doesn't work in C# so what's the next best thing?

*编辑*
我更改了性能标准,因为一些讨论。性能通常不是这里的限制因素,因此更正确的目标应该是不变得不合理,而不是有史以来最快。

* Edit * I changed my performance criteria because of some of the discussion. Performance is generally not a limiting factor here, so the goal more correctly should be to not be unreasonable, not to be the fastest ever.

我不喜欢其他实现的原因我建议是因为它们要么重复代码,从而留下了更改一个部分的空间,而没有另一个部分,或者对于我通常选择的部分,则需要撤消该操作,这需要额外的思考和时间才能撤消刚刚做的事情。特别是在使用字符串操作时,这通常会导致您因一个错误或无法解决空数组而试图撤消未发生的错误。

The reason I dislike the alternate implementations I suggest is because they either duplicate code which leaves room for changing one part and not the other or for the one I generally choose it requires "undoing" the operation which requires extra thought and time to undo the thing that you just did. With string manipulation in particular this usually leaves you open for off by one errors or failing to account for an empty array and trying to undo something that didn't happen.

推荐答案

对于您的特定示例,有一个标准解决方案: string.Join 。这样可以正确添加定界符,这样您就不必自己编写循环。

For your specific example there is a standard solution: string.Join. This handles adding the delimiter correctly so that you don't have to write the loop yourself.

如果您真的想自己编写此循环,可以使用以下方法:

If you really want to write this yourself an approach you can use is the following:

string delimiter = "";
foreach (var element in array)
{
    append(delimiter);
    append(element);
    delimiter = ",";
}

这应该是合理有效的,我认为阅读是合理的。常量字符串,被插入,因此不会导致每次迭代都创建新的字符串。当然,如果性能对您的应用程序至关重要,则应该进行基准测试而不是猜测。

This should be reasonably efficient and I think it is reasonable to read. The constant string "," is interned so this won't result in a new string being created on each iteration. Of course if performance is critical for your application you should benchmark rather than guess.

这篇关于处理“循环初始化”的其他方式包括:在C#中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆