跳转到代码C#中的特定行

Jump to certain line in code C#

我有一些方法是从其他一些方法中调用的。当在某些方法中执行某个操作时,我想回到第一个方法并跳过其余代码。目前,我使用 booleans 来检查程序的 "status" 但我想避免这种情况,因为这些方法应该是 void 因为本质上它们不需要 return 任何东西。我找到了 goto 之类的东西,但它只适用于相同的方法。

问题:有没有办法在C#中用不同的方法跳转到代码中的特定点?我找到了其他语言的东西,但 C# 上的东西不多。

现状:

    void test1()
    {
        bool status = test2();

        if (!status)
            return; // the other stuff will not get done

        Debug.WriteLine("Initialization OK");
    }

    bool test2()
    {
        bool status = test3();

        if (!status)
            return false; // the other stuff will not get done

        // do other stuff 
        return true;
    }

    bool test3()
    {
        if (xxx)
            return false; // the other stuff will not get done
        else
            // do other stuff 
            return true;
    }

想要的情况:

    void test1()
    {
        test2();

        // do other stuff
        Debug.WriteLine("Initialization OK");

        GOTOHERE:
             Debug.WriteLine("Initialization NOT OK");
    }

    void test2()
    {
        test3();            
        // do other stuff 
    }

    void test3()
    {
        if (xxx)
            **GOTOHERE**; // Go directly to the location in test1() so that all unnecessary code is skipped

        // do other stuff
    }

从你的方法中返回一些东西来指示你之后应该做什么正是你应该做的。因此 return 一个布尔值,指示 test2test3 是否成功,并使用该值指示是否要继续进行。现在不要使用 goto,因为它只会导致难以维护的意大利面条代码。要确定在什么情况下控制流应该跳转到 GOTOHERE,您需要扫描整个代码以查找特定的 goto 语句。

在您的情况下,您想指出某些初始化代码是否工作正常。因此你也可以抛出异常:

void test3()
{
    if (xxx)
        throw new Exception("Some text");

    // do other stuff
}

这样您就不需要 return 您的方法中的任何内容,而是适当地处理异常:

void test1()
{
    try { test2(); }
    catch { 
        // some exception-handling such as logging
        return; 
    }

    Debug.WriteLine("Initialization OK");
}

这样做的好处是,如果 test3 成功,您不需要签入 test2,允许您让异常 冒泡通过 您的方法,直到最终由 catch 处理。如果在整个调用堆栈中未找到 catch,您的应用可能会终止。

我不推荐它,但对您的问题的简单回答是使用 goto 语句。

参见:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/goto

但是,您确实应该从之前的方法调用中返回值,您可以使用这些值来确定是否需要 运行 其他代码。

您也可以 throw 例外,但一般来说我不喜欢使用它们来控制流程,除非情况特殊(我想这就是这个名字的由来)。如果您希望控制可以这样或那样流动,那也不例外。

C# 确实有 goto 关键字,它的作用与其他语言一样。将标签声明为 label_you_want_to_jump_to:,并使用 goto label_you_want_to_jump_to (https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/goto).

既然这么说了,使用 goto 通常是个坏主意,尤其是在这种情况下。通过稍微重构一下,您的问题可能会更容易解决。将test3拆分成两个函数,减少嵌套量可能是这样一种方式。您也可以在 test3 中抛出异常,并在 test1 中捕获它。这完全取决于你想做什么。

得知 C# 实际上支持 GOTO 命令,我感到很惊讶。但它旨在允许退出深层嵌套循环。

这篇文章对此进行了解释并给出了很多例子:https://www.dotnetperls.com/goto

不过

除非你还在 1970 年编码,否则使用 GOTO 被认为是非常糟糕的做法。这使得代码维护变得非常困难。它甚至会导致问题和性能问题,并使 JIT 编译器的生活更加困难。

The go to statement as it stands is just too primitive, it is too much an invitation to make a mess of one's program.

Edsger W. Dijkstra

如果你去掉显式布尔值(这是多余的),我认为你的(相当人为的)例子看起来很多"cleaner":

void test1()
{
    if (test2())
    {
        Debug.WriteLine("Initialization OK");
    }
}

bool test2()
{
    return test3();
}

bool test3()
{
    return xxx;
}

我也更喜欢使用正面条件而不是负面条件,所以 "if (true)" 而不是 "if (!false)"。这避免了更难理解的双重否定。

实际上我们正在使用 Predicate Logic。我们可以使用正常的逻辑运算符组合我们的谓词(比 return bool 没有副作用的方法)。考虑这个例子:

bool test4()
{
    if (test1())
    {
        if (test2())
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }
}

我们注意到这只是 test1 和 test2 的逻辑合取(和),因此可以简单地使用 && 合取运算符使这一点更清楚:

bool test4()
{
    return test1() && test2();
}

与逻辑析取(或)类似:

bool test5()
{
    if (test1())
    {
        return true;
    }
    else if (test2())
    {
        return true;
    }
    else 
    {
        return false;
    }
}

我们可以这样写:

bool test5()
{
    return test1() || test2();
}

我明白你的意思但是打破事件的顺序(又名跳跃)不是好的做法。您的代码变得不可读,因为 reader 需要从一个地方跳转到另一个地方。无法跳出当前方法是有原因的:

接下来是真正简化的解释。我正在掩盖许多细节。
如果您了解 how the stack works,您就会知道运行时将为每个新方法调用将一个新的 堆栈帧 推入堆栈。新的栈帧包含方法的局部变量以及其他实现细节。如果您想跳转到另一个方法,运行时需要将一个新的 堆栈框架 推入您的堆栈,以便为该方法创建那些局部变量。所以你的 goto 将成为一个方法调用而不是一个跳转语句。这很奇怪,而不是 you/we 想要的。在这种情况下使用普通方法调用而不是跳转语句。

有广泛接受的跳跃语句,如 returnbreakcontinue
goto 不是其中之一,尽管我认为 goto case 在某些情况下是一个有效的解决方案。

返回有关下一步操作的信息是此处的正确行为。
我确实同意,从语义的角度来看,返回 bool 不是很有表现力,至少不是您当前的方法名称。命名改进建议:

void DoTest1();
bool TryTest2();
bool TryTest3();

仅供参考

bool flag;

void test1()
{
    test2();

    if (flag) {
        // do other stuff
        Debug.WriteLine("Initialization OK");
    }
    else {
         Debug.WriteLine("Initialization NOT OK");
    }
}

void test2()
{
    test3();            
    if (flag) {
        // do other stuff 
    }
}

void test3()
{
    if (xxx)
        return;

    // do other stuff

    flag = true;
}