C# 是否有必要在循环后调用'yield break'?

C# 是否有必要在循环后调用'yield break'?,c#,C#,在我的代码中,我有这样一个方法 public static IEnumerable<int> GetDiff(int start, int end) { while (start < end) { yield return start; start++; } yield break; // do we need to call it explicitly? } 公共静态IEnumerable GetDif

在我的代码中,我有这样一个方法

public static IEnumerable<int> GetDiff(int start, int end)
{
    while (start < end)
    {
        yield return start;
            start++;
    }
    yield break; // do we need to call it explicitly?
}
公共静态IEnumerable GetDiff(int-start,int-end)
{
while(开始<结束)
{
收益率-收益率开始;
启动++;
}
yield break;//我们需要显式地调用它吗?
}

因此,我感兴趣的测试用例是
GetDiff(1,5)
GetDiff(5,1)
。虽然很清楚第一种情况下会发生什么,但不太清楚如何在第二种情况下完成而不出现
收益率中断循环后

否这不是必需的。它将在以下方面发挥作用:

public static IEnumerable<int> GetDiff(int start, int end)
{
    while (start < end)
    {
        yield return start;
        start++;
    }
    // yield break; - It is not necessary. It is like `return` which does not return a value.
}
公共静态IEnumerable GetDiff(int-start,int-end)
{
while(开始<结束)
{
收益率-收益率开始;
启动++;
}
//屈服断裂;-这是不必要的。它就像不返回值的“return”。
}
在这种情况下,函数的执行只需退出即可结束

但你可以这样写:

public static IEnumerable<int> GetDiff(int start, int end)
{
    while (true)
    {
        if (start >= end)
            yield break;
        yield return start;
        start++;
    }
    Console.WriteLine("Finish"); // note that this line will not be executed
}
// <GetDiff>d__1
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;

[CompilerGenerated]
private sealed class <GetDiff>d__1 : IEnumerable<int>, IEnumerable, IEnumerator<int>, IDisposable, IEnumerator
{
    private int <>1__state;

    private int <>2__current;

    private int <>l__initialThreadId;

    private int start;

    public int <>3__start;

    private int end;

    public int <>3__end;

    int IEnumerator<int>.Current
    {
        [DebuggerHidden]
        get
        {
            return <>2__current;
        }
    }

    object IEnumerator.Current
    {
        [DebuggerHidden]
        get
        {
            return <>2__current;
        }
    }

    [DebuggerHidden]
    public <GetDiff>d__1(int <>1__state)
    {
        this.<>1__state = <>1__state;
        <>l__initialThreadId = Environment.CurrentManagedThreadId;
    }

    [DebuggerHidden]
    void IDisposable.Dispose()
    {
    }

    private bool MoveNext()
    {
        switch (<>1__state)
        {
        default:
            return false;
        case 0:
            <>1__state = -1;
            break;
        case 1:
            <>1__state = -1;
            start++;
            break;
        }
        if (start < end)
        {
            <>2__current = start;
            <>1__state = 1;
            return true;
        }
        return false;
    }

    bool IEnumerator.MoveNext()
    {
        //ILSpy generated this explicit interface implementation from .override directive in MoveNext
        return this.MoveNext();
    }

    [DebuggerHidden]
    void IEnumerator.Reset()
    {
        throw new NotSupportedException();
    }

    [DebuggerHidden]
    IEnumerator<int> IEnumerable<int>.GetEnumerator()
    {
        <GetDiff>d__1 <GetDiff>d__;
        if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
        {
            <>1__state = 0;
            <GetDiff>d__ = this;
        }
        else
        {
            <GetDiff>d__ = new <GetDiff>d__1(0);
        }
        <GetDiff>d__.start = <>3__start;
        <GetDiff>d__.end = <>3__end;
        return <GetDiff>d__;
    }

    [DebuggerHidden]
    IEnumerator IEnumerable.GetEnumerator()
    {
        return System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator();
    }
}
公共静态IEnumerable GetDiff(int-start,int-end)
{
while(true)
{
如果(开始>=结束)
屈服断裂;
收益率-收益率开始;
启动++;
}
Console.WriteLine(“Finish”);//注意这一行不会被执行
}

将您的代码放入编译器中,构建并反向工程回C#,结果如下:

using System.Collections.Generic;

public static IEnumerable<int> GetDiff(int start, int end)
{
    while (start < end)
    {
        yield return start;
        start++;
    }
}

d_u1
如下所示:

public static IEnumerable<int> GetDiff(int start, int end)
{
    while (true)
    {
        if (start >= end)
            yield break;
        yield return start;
        start++;
    }
    Console.WriteLine("Finish"); // note that this line will not be executed
}
// <GetDiff>d__1
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;

[CompilerGenerated]
private sealed class <GetDiff>d__1 : IEnumerable<int>, IEnumerable, IEnumerator<int>, IDisposable, IEnumerator
{
    private int <>1__state;

    private int <>2__current;

    private int <>l__initialThreadId;

    private int start;

    public int <>3__start;

    private int end;

    public int <>3__end;

    int IEnumerator<int>.Current
    {
        [DebuggerHidden]
        get
        {
            return <>2__current;
        }
    }

    object IEnumerator.Current
    {
        [DebuggerHidden]
        get
        {
            return <>2__current;
        }
    }

    [DebuggerHidden]
    public <GetDiff>d__1(int <>1__state)
    {
        this.<>1__state = <>1__state;
        <>l__initialThreadId = Environment.CurrentManagedThreadId;
    }

    [DebuggerHidden]
    void IDisposable.Dispose()
    {
    }

    private bool MoveNext()
    {
        switch (<>1__state)
        {
        default:
            return false;
        case 0:
            <>1__state = -1;
            break;
        case 1:
            <>1__state = -1;
            start++;
            break;
        }
        if (start < end)
        {
            <>2__current = start;
            <>1__state = 1;
            return true;
        }
        return false;
    }

    bool IEnumerator.MoveNext()
    {
        //ILSpy generated this explicit interface implementation from .override directive in MoveNext
        return this.MoveNext();
    }

    [DebuggerHidden]
    void IEnumerator.Reset()
    {
        throw new NotSupportedException();
    }

    [DebuggerHidden]
    IEnumerator<int> IEnumerable<int>.GetEnumerator()
    {
        <GetDiff>d__1 <GetDiff>d__;
        if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
        {
            <>1__state = 0;
            <GetDiff>d__ = this;
        }
        else
        {
            <GetDiff>d__ = new <GetDiff>d__1(0);
        }
        <GetDiff>d__.start = <>3__start;
        <GetDiff>d__.end = <>3__end;
        return <GetDiff>d__;
    }

    [DebuggerHidden]
    IEnumerator IEnumerable.GetEnumerator()
    {
        return System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator();
    }
}
它正在检查使用者是否是同一个线程,并且状态没有改变(从原始的
-2
),如果保持不变,它将返回自身。否则,它将返回一个克隆。这意味着,如果从另一个线程调用
GetEnumerator
,或者在迭代开始后由同一个线程调用,则返回的
IEnumerator
将从一开始就启动(应该如此)

还要注意,
GetEnumerator
将状态更改为
0
。这很重要

现在,请注意
MoveNext
方法。它是与您的代码等效的状态机:

private bool MoveNext()
{
    switch (<>1__state)
    {
    default:
        return false;
    case 0:
        <>1__state = -1;
        break;
    case 1:
        <>1__state = -1;
        start++;
        break;
    }
    if (start < end)
    {
        <>2__current = start;
        <>1__state = 1;
        return true;
    }
    return false;
}

那么,
的收益率是多少做什么?在这种情况下,什么都没有<代码>屈服断裂
用于指示状态机应该结束(
MoveNext
返回
false
),但是状态机无论如何都会在那里结束,因为它是方法的结束。因此,您只会发现
屈服断裂当它不在方法末尾时有用(且有意义)。例如,请参见


此外,我还认为添加
会产生中断对代码的可维护性或可读性没有帮助。

没有。谁教你的?“如何完成”是什么意思?它只是到达过程的末尾。屈服中断就像一个线程到达其函数的末尾并终止。@Frenchy,嗯<代码>屈服断裂就像是
中断
for
循环中。@john,当你使用收益率时,你使用的生成器将永远不会停止。停止发电机。。而且不会返回值…但这不是必需的…谢谢,回答得很好!因此编译器为您返回
MoveNext=false
,我们不需要在方法末尾显式地
产生break
[DebuggerHidden]
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
     <GetDiff>d__1 <GetDiff>d__;
    if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
    {
        <>1__state = 0;
        <GetDiff>d__ = this;
    }
    else
    {
        <GetDiff>d__ = new <GetDiff>d__1(0);
    }
    <GetDiff>d__.start = <>3__start;
    <GetDiff>d__.end = <>3__end;
    return <GetDiff>d__;
}
private bool MoveNext()
{
    switch (<>1__state)
    {
    default:
        return false;
    case 0:
        <>1__state = -1;
        break;
    case 1:
        <>1__state = -1;
        start++;
        break;
    }
    if (start < end)
    {
        <>2__current = start;
        <>1__state = 1;
        return true;
    }
    return false;
}
{
    E e = ((C)(x)).GetEnumerator();
    try {
        while (e.MoveNext()) {
            V v = (V)(T)e.Current;
            embedded_statement
        }
    }
    finally {
        ... // Dispose e
    }
}