C#:嵌套条件语句与 continue 语句

发布于 2024-09-12 05:02:24 字数 683 浏览 16 评论 0原文

最近使用 ReSharper 时,建议我通过反转 if 条件并使用 continue 语句来减少某些地方的嵌套。

嵌套条件:

foreach(....)
{
    if(SomeCondition)
    {
        //do some things

        if(SomeOtherNestedCondition)
        {
            //do some further things
        }
    }
}

继续语句:

foreach(....)
{
    if(!SomeCondition) continue;

    //do some things

    if(!SomeOtherNestedCondition) continue;

    //do some further things
}

我理解为什么您希望减少性能和内存问题的嵌套的一些逻辑,以及这两个片段如何相互等同其他,但是从我的开发背景来看,之前示例在阅读代码时更容易理解。

您更喜欢哪种方法?为什么?您是否在日常代码中使用 continue 来代替嵌套的 if 语句?

In using ReSharper recently, it is suggesting I reduce nesting in certain places by inverting if conditions and using the continue statements.

nested conditionals:

foreach(....)
{
    if(SomeCondition)
    {
        //do some things

        if(SomeOtherNestedCondition)
        {
            //do some further things
        }
    }
}

continue statements:

foreach(....)
{
    if(!SomeCondition) continue;

    //do some things

    if(!SomeOtherNestedCondition) continue;

    //do some further things
}

I understand some of the logic of why you'd want to reduce nesting for performance and memory issues as well as how the two snippets equate to each other, however from my development background, the before example is easier to follow when reading the code.

Which approach do you prefer and why? Do you use continue over nested ifs in your everyday code?

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

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

发布评论

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

评论(10

半步萧音过轻尘 2024-09-19 05:02:25

简短的回答:

我倾向于使用缩进,这意味着发生了一些真正的决策逻辑,即。预期有多个可能执行路径的逻辑。

更长的答案:

通常更喜欢缩进块而不是前面的“中断”语句(继续breakreturn抛出)。

原因:在我看来,破坏语句通常会使代码更难阅读。如果缩进代码,很容易找到某些决策逻辑发生的位置:这将是缩进较少的代码的第一行。如果您使用带有反转条件的中断语句,则必须做更多的工作来了解代码如何分支以及在什么情况下跳过某些代码。

对我来说有一个值得注意的例外,即在方法开头验证参数。我将此代码格式化如下:

if (thisArgument == null) throw new NullArgumentException("thisArgument");
if (thatArgument < 0) throw new ArgumentOutOfRangeException("thatArgument");
...

原因:因为我不希望实际抛出这些异常(也就是说,我希望正确调用该方法;调用函数负责检测无效输入) ,IMO),我不想缩进所有其余的代码来处理不应该发生的事情。

Short answer:

I tend to use indentation such that it implies that some real decision logic takes place, ie. logic where more than one possible execution path is expected.

Longer answer:

I usually prefer indented blocks to preceding "breaking" statements (continue, break, return, or throw).

Reason: In my opinion, breaking statements generally make code harder to read. If you indent code, it's easy to find the location where some decision logic happens: that'll be the first line further up the code that is indented less. If you use breaking statements with an inverted condition instead, you have to do more work to understand how code branches and under which circumstances certain code is skipped.

There is one notable exception for me, namely validating arguments at the beginning of a method. I format this code as follows:

if (thisArgument == null) throw new NullArgumentException("thisArgument");
if (thatArgument < 0) throw new ArgumentOutOfRangeException("thatArgument");
...

Reason: Since I don't expect these exceptions to be actually thrown (that is, I expect the method to be invoked correctly; the calling function is responsible to detect invalid input, IMO), I don't want to indent all the rest of the code for something that shouldn't happen.

酒几许 2024-09-19 05:02:25

使用 continue 样式代码;您将如何处理不依赖于 SomeOtherNestedCondition 的第三个操作,这使得代码的顺序很重要,IMO 使其难以维护。

例如:

foreach(....) 
{ 
    if(!SomeCondition) continue; 

    //do some things 

    if(!SomeOtherNestedCondition) continue; 

    //do some further things 

    if(!SomeSecondNonNestedCondition) continue;

    // do more stuff
}

当 SomeOtherNestedCondition 导致 continue; 发生,但 SomeSecondNonNestedCondition 仍应执行时,会发生什么?

我会重构每一位“代码”,并使用嵌套的 if() 来调用每个重构的方法,并且保留嵌套结构。

With the continue style code; how would you handle a third operation that isn't dependent on SomeOtherNestedCondition, this makes the order of the code important which IMO makes it less maintainable.

For example:

foreach(....) 
{ 
    if(!SomeCondition) continue; 

    //do some things 

    if(!SomeOtherNestedCondition) continue; 

    //do some further things 

    if(!SomeSecondNonNestedCondition) continue;

    // do more stuff
}

What happens when SomeOtherNestedCondition causes the continue; to happen, but SomeSecondNonNestedCondition should still execute?

I would refactor out each bit of "code" and use nested if()s to call each refactored method, and I'd keep the nested structure.

清风无影 2024-09-19 05:02:25

结合使用两者。我在循环顶部使用 if(condition) continue;if(condition) return; 来验证当前状态,并嵌套 if 进一步声明以控制我想要完成的任何事情的流程。

Use a combination of the two. I use if(condition) continue; and if(condition) return; at the top of the loop to validate the current state, and nested if statements further down to control the flow of whatever I'm trying to accomplish.

简单的回答。哪一个更容易阅读和理解。

Simple answer. Which ever one is easier to read and understand.

别在捏我脸啦 2024-09-19 05:02:25

在内存或性能方面没有区别。底层 IL 只是分支/跳转指令的选择,因此它们是否跳回循环顶部或“else”语句并不重要。

您应该选择更容易阅读的一个。我个人更喜欢避免“继续”,但如果您有很多级别的嵌套,那么您的第二个示例可能更容易理解。

There is no difference in terms of memory or performance. The underlying IL is just a selection of branch/jump instructions so it doesn't really matter whether they jump back to the top of the loop or to the "else" statement.

You should pick whichever is easier to read. I personally prefer to avoid 'continue', but if you have many levels of nesting then your second example can be easier to follow.

宁愿没拥抱 2024-09-19 05:02:25

使用 continue 使大部分代码处于常规过程代码的级别。
否则,如果有五个检查,您将缩进方法的“内容”10 或 20 个字符,具体取决于缩进大小,而这些是 10/20 个字符,您必须滚动才能看到更长的行。

Using continues makes the bulk of the code on the level of regular procedural code.
Otherwise, if there are five checks, you'll indent the "meat" of the method 10 or 20 chars, depending on the indent size, and those are 10/20 chars that you'll have to scroll to see the longer lines.

早乙女 2024-09-19 05:02:25

Continue 原意:当任何条件为 false 时,代码不会被处理。这是情况的示例:

class Program
{
    static bool SomeCondition = false;
    static bool SomeOtherNestedCondition = false;
    static void Main(string[] args)
    {    
        for (int i = 0; i < 2; i++)
        {
            if (SomeCondition)
            {
                //do some things

                if (SomeOtherNestedCondition)
                {
                    //do some further things
                }
            }
            Console.WriteLine("This text appeared from the first loop.");
        }
        for (int i = 0; i < 2; i++)
        {
            if (!SomeCondition) continue;

            //do some things

            if (!SomeOtherNestedCondition) continue;

            //do some further things
            Console.WriteLine("This text appeared from the second loop.");
        }
        Console.ReadLine(); 
    }
}

输出将是:
在此处输入图像描述

Original continue meaning: The code won't be processed while any condition is false. Here is an example of the situation:

class Program
{
    static bool SomeCondition = false;
    static bool SomeOtherNestedCondition = false;
    static void Main(string[] args)
    {    
        for (int i = 0; i < 2; i++)
        {
            if (SomeCondition)
            {
                //do some things

                if (SomeOtherNestedCondition)
                {
                    //do some further things
                }
            }
            Console.WriteLine("This text appeared from the first loop.");
        }
        for (int i = 0; i < 2; i++)
        {
            if (!SomeCondition) continue;

            //do some things

            if (!SomeOtherNestedCondition) continue;

            //do some further things
            Console.WriteLine("This text appeared from the second loop.");
        }
        Console.ReadLine(); 
    }
}

And output will be:
enter image description here

水水月牙 2024-09-19 05:02:25

但是从我的开发背景来看,前面的示例在阅读代码时更容易理解。

嗯 - 我想,这是你的个人意见。例如,我尝试避免这种嵌套,因为在我看来,这会使代码更难阅读。

如果您比“之后”版本更喜欢“之前”版本,请使用它。
只需配置 ReSharper,它就会建议您真正想要的内容。

永远记住:ReSharper 是一个相当“愚蠢”的重构工具——它无法取代开发人员。它只能通过做一些愚蠢的复制和粘贴工作来帮助他。
即使在 ReSharper 建议相反重构的情况下,ReSharper 所做的一些重构也会导致结果。

因此,不要将 ReSharper 的建议视为最佳实践,而应将其视为您可以采取的可能性。

顺便说一句:您应该在这里考虑性能因素 - 如果性能确实存在显着差异,我会感到惊讶。

however from my development background, the before example is easier to follow when reading the code.

Well - I think, that's your personal opinion. I - for example - try to avoid such nesting as it makes the code harder to read in my opinion.

If you like the "before" version more than the "after" one, use it.
Just configure ReSharper so it suggests what you really want it to.

Always keep in mind: ReSharper is a quite "dumb" refactoring tool - it cannot replace the developer. It can only help him by doing some otherwise stupid copy&paste work.
Some refactorings done by ReSharper result even in situations in whcih ReSharper suggests the opposite refactoring.

Therefore, don't see ReSharper's suggestions as best practices but as possibilities you could do.

BTW: You should be driven by performance considerations here - I would be surprised if there are really notable differences in performance.

对岸观火 2024-09-19 05:02:24

一般来说,我发现最好总是以任何排除的条件开始语句块,因为它会降低复杂性,但更重要的是在进一步执行之前抛出不兼容的情况,这可以提高代码和内存性能。这也确保了您的条件在维护期间的安全性,即不太可能将无效场景传递到不属于它们的代码中。

另外,我认为两者中的第二个个人更具可读性,因为您没有作用域层混淆了可用的内容,很容易在以后的某一层中创建一个变量,而没有意识到它在另一层中不可用,或者必须管理它们以进行适当的修改等。

这不仅仅是继续循环,而是这也指方法应返回的条件; 而不是让方法启动

if (valid)
{
    do stuff;
}

它应该始终启动,

if (notValid)
{
    return;
}

As a rule I have found it best to always start statement blocks with any conditions that will except out as it reduces complexity, but more importantly throws out non-compatible circumstances before they are stepped any further which can increase code and memory performance. This also ensures safety of your conditions over a duration through maintenance, that it's less likely to have invalid scenarios passed into code they don't belong in.

Plus I think the second of the two is more readable personally because you don't have the scope layers confusing what's available, it's easy to create a variable in one layer later down the road and not realize it's unavailable in another layer, or having to manage them to be modified appropriately etc.

This isn't just continue in loops, but this also refers to conditions of methods should return; instead of having a method start

if (valid)
{
    do stuff;
}

it should always start

if (notValid)
{
    return;
}
自此以后,行同陌路 2024-09-19 05:02:24

不应该有显着的性能差异,这都是关于可读性的。我个人认为后者更容易阅读。更少的嵌套,更容易阅读。

There should be no significant performance different, this is all about readability. Personally I think the latter is easier to read. Less nesting, easier to read.

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