newbie C# - 如何在while循环中创建goto语句?

时间:2016-05-20 16:21:42

标签: c#

我怎么能让这个IL_ABC goto语句进入这个while循环?如果不可能的话,我可以得到一个解释为什么它被禁止,以及代码中的修改是否同样有效?非常感谢!!!

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;

namespace test.Properties
{
    internal class Testing
    {
        public Testing()
        {
            Data.smethod_0();
        }

        [DllImport("myfile.dll")]
        public static extern bool EM(int int0, string string0);

        public static void smethod_0(object object0)
        {
            try
            {
                while (true)
                {
                IL_ABC:
                    Process[] processesByName = Process.GetProcessesByName("dummy");
                    if (processesByName.Length == 1)
                    {
                        if (Testing.EM(processesByName[0].Id, "a.dll"))
                        {
                            processesByName[0].Kill();
                            Thread.Sleep(2000);
                            continue;
                        }
                        Thread.Sleep(2000);
                        if (Testing.EM(processesByName[0].Id, "b.dll"))
                        {
                            processesByName[0].Kill();
                            Thread.Sleep(2000);
                            continue;
                        }
                    }
                    Thread.Sleep(2000);
                }
            }
            catch (Exception ex)
            {
                Debug.smethod_0("Error! " + ex.Message);
                Thread.Sleep(2000);
                goto IL_ABC;
            }
        }
    }
}

3 个答案:

答案 0 :(得分:4)

  

"如果不可能,我可以解释为什么禁止它"

忽略代码的问题(其他现有的答案地址)我试图解释为什么。以下是C# Language Specifications

的引用
  

如果当前函数成员中不存在具有给定名称的标签,或者如果goto语句不在标签的范围内,则会发生编译时错误。此规则允许使用goto语句将控制权移出嵌套作用域,但不能转移到嵌套作用域中。

当执行到您的GOTO声明时,您的标签已超出范围且不再有效。您可以通过在while循环中声明一个整数并尝试在catch块中访问它来测试它。

答案 1 :(得分:2)

请勿使用goto

相反,您可以像这样编写代码:

while (true)
{
    try
    {
        Process[] processesByName = Process.GetProcessesByName("dummy");
        if (processesByName.Length == 1)
        {
            if (Testing.EM(processesByName[0].Id, "a.dll"))
            {
                processesByName[0].Kill();
                Thread.Sleep(2000);
                continue;
            }
            Thread.Sleep(2000);
            if (Testing.EM(processesByName[0].Id, "b.dll"))
            {
                processesByName[0].Kill();
                Thread.Sleep(2000);
                continue;
            }
        }
        Thread.Sleep(2000);
    }

    catch (Exception ex)
    {
        Debug.smethod_0("Error! " + ex.Message);
        Thread.Sleep(2000);
    } 
}

答案 2 :(得分:0)

在内部块范围内直接使用GOTO对开发人员来说很方便,但这对编译器编写者来说是一个很大的麻烦。问题在于,在进入任何块的范围时,您的程序都应该在后台做某些事情。就像在进入try-catch块时一样,它应该在堆栈上创建一个特殊的框架,在进入常规块时,它应该分配所有作用域局部变量,在进入for循环体时,它应该执行其初始化程序,依此类推。如果您只是在嵌套块内的某个随机点处跳转,那么所有这些内容都将被绕过,并且程序将简单地崩溃。从理论上讲,编译器可以在处理GOTO跳转时针对所有可能的情况解决并提交这些内容,但是实际上,在C#编译器中创建此类功能所花费的工作量不值得您拥有它。因此,在C#中仅禁用了进入嵌套内部范围的GOTO,并且所有块都必须具有单个入口点,这是该块的左开口括号。 在您的特定情况下,您只需将IL_ASM标签移到try-catch块之外(就在'try'关键字之前),它将起作用,但是更合适的方法是使用以下构造:

        bool repeat = true;
        while (repeat)
        {
            try
            {  
                ... do something...
                repeat = false;
            }
            catch
            {
            }
        }