Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在现代.NET代码中使用goto有什么理由吗?_C#_.net_Goto - Fatal编程技术网

C# 在现代.NET代码中使用goto有什么理由吗?

C# 在现代.NET代码中使用goto有什么理由吗?,c#,.net,goto,C#,.net,Goto,我刚刚在.NET基本库的reflector中找到了这段代码 if (this._PasswordStrengthRegularExpression != null) { this._PasswordStrengthRegularExpression = this._PasswordStrengthRegularExpression.Trim(); if (this._PasswordStrengthRegularExpression.Length

我刚刚在.NET基本库的reflector中找到了这段代码

    if (this._PasswordStrengthRegularExpression != null)
    {
        this._PasswordStrengthRegularExpression = this._PasswordStrengthRegularExpression.Trim();
        if (this._PasswordStrengthRegularExpression.Length == 0)
        {
            goto Label_016C;
        }
        try
        {
            new Regex(this._PasswordStrengthRegularExpression);
            goto Label_016C;
        }
        catch (ArgumentException exception)
        {
            throw new ProviderException(exception.Message, exception);
        }
    }
    this._PasswordStrengthRegularExpression = string.Empty;
Label_016C:
    ... //Other stuff
我听过所有的斯皮尔的“你不应该因为害怕永远被流放到地狱而使用goto”。我一直对coders女士给予相当高的评价,虽然我可能不同意他们的所有决定,但我始终尊重他们的推理

那么,我缺少这样的代码有什么好的理由吗?这段代码摘录是由一个不称职的开发人员编写的吗?或者.NET reflector返回的代码不准确

我希望有一个好的理由,我只是盲目地错过了


感谢大家的投入

我还没有在写过和审阅过的许许多多行.NET代码中看到Goto的有效案例


在不支持使用finally块进行结构化异常处理的语言中(PASCAL是结构化编程语言和经典C语言的祖父),战术上使用GOTO可以使代码在嵌套循环内执行终止时执行清理时更易于理解(与正确设置多个循环终止条件相反)。即使在那一天,我个人也没有因为这个原因使用goto(可能是因为害怕“永远流放到地狱里”)。

你不应该看反射器代码

虽然如果你看过反汇编的IL,你会看到到处都是gotos。本质上,我们使用的所有循环和其他控制结构都转换成了gotos,只是通过将它们转换成代码中的结构,它变得更可读,更易于维护


顺便说一句,我不认为您发布的代码是使用goto的好地方,我很难想到一个。

有一个有效的例子——当您试图模拟递归过程调用并在非递归代码中返回时,或者做类似的事情时(这种需求也发生在Prolog解释器中)但是一般来说,除非你正在做一些需要微优化的事情,比如象棋程序或语言解释器,否则最好只使用常规过程堆栈和函数/过程调用。

它可能不在源代码中,这只是反汇编代码的外观。

不,没有很好的理由使用
goto
。我上一次编写一个
goto
语句是在1981年,从那以后我就没有错过过这个特殊的构造。

我见过goto用来打破嵌套循环:


我不认为这样使用它有什么错。

除了所有这些好的有效的东西,当你在查看反汇编代码时,请记住,开发人员可能在这些程序集上使用了模糊处理程序。模糊处理的一种技术是向IL添加随机goto。看看状态图。如果你相信要使用的最佳代码结构是最直接、最清楚地表达您的意图的代码结构,那么这些状态转换中的每一个都应该被编码为goto

然而,在现实世界中,这种情况往往会出现故障。第一个问题是,我们经常需要停止机器,退出到其他代码,然后重新启动机器——这意味着这些转换中的每一个都是对状态变量的更改,用于在switch/case语句中标识正确的状态。这实际上只是一种隐藏方式延迟goto-写入状态变量与写入程序计数器寄存器没有太大区别,实际上,这只是实现“goto在那里-但不是现在,以后”的一种方法

不过,在某些情况下,goto可以很好地表达某种状态模型中正在发生的事情——我猜一个例子就是医生有时使用的诊断流程图。如果你将其中一个作为一个程序来实现,而不使用goto进行转换,那么实际上你只是在给自己制造麻烦加密代码的意图


只是到目前为止,最常见的情况不太可能是手工编写的代码。我已经编写了代码生成器,为各种状态模型(决策处理、常规语法解析等)中的转换生成goto语句但是我不记得上一次我在手写代码中使用goto是什么时候了。

我在编写FORTRAN时甚至都没有使用GO TO back进行过编码


我从未使用过它。我不明白为什么任何现代语言都会要求用户使用这样的东西。我会毫不含糊地说“不”.

goto对于C等语言中的清理内容是非常有效的,至少在某种程度上它模拟了异常的概念。我确信.NET有更好的方法来处理类似的内容,所以goto已经过时并且容易出错。

goto在编写解析器和词法分析器时经常很有用。

Reflector并不完美此方法的所有代码可从参考源获得。它位于ndp\fx\src\xsp\system\web\security\admembershipprovider.cs中:

        if( passwordStrengthRegularExpression != null )
        { 
            passwordStrengthRegularExpression = passwordStrengthRegularExpression.Trim();
            if( passwordStrengthRegularExpression.Length != 0 ) 
            { 
                try
                { 
                    Regex regex = new Regex( passwordStrengthRegularExpression );
                }
                catch( ArgumentException e )
                { 
                    throw new ProviderException( e.Message, e );
                } 
            } 
        }
        else 
        {
            passwordStrengthRegularExpression = string.Empty;
        }
请注意,它是如何检测不到最后一个else子句并用goto进行补偿的。几乎可以肯定,它是被if()语句中的try/catch块绊倒的


很明显,您希望使用实际的源代码,而不是反编译版本。注释本身非常有用,您可以相信源代码是准确的。好吧,大多数情况下是准确的,有一个错误的后处理工具删除了Microsoft程序员的名字,造成了一些轻微的损坏。标识符有时是r用破折号替换,代码重复两次。您可以下载源代码。

我不喜欢那个代码


我更愿意将正则表达式存储在成员中,并在设置时对其进行验证,从而避免在读取时对逻辑的所有需要。

关于这一点:

那么,是否有充分的理由编写代码 就像我错过的那样?是吗 代码摘录由一个 糟糕的开发人员?还是.NET reflector 返回不准确的代码

我不同意这个观点
int i = 1;
switch (i)
{
case 1:
  printf ("Case 1\r\n");
case 2:
  printf ("Case 2\r\n");
default:
  printf ("Default Case\r\n");
  break;
}
Case 1 Case 2 Default Case
int i = 1;
switch (i)
{
case 1:
  Console.Writeline ("Case 1");
case 2:
  Console.Writeline ("Case 2");
default:
  Console.Writeline ("Default Case");
  break;
}
Control cannot fall through from one case label ('case 1:') to another
int i = 1;
switch (i)
{
case 1:
    Console.WriteLine ("Case 1");
    goto case 2;
case 2:
    Console.WriteLine("Case 2");
    goto default;
default:
    Console.WriteLine("Default Case");
    break;
}
private IDynamic ToExponential(Engine engine, Args args)
{
    var x = engine.Context.ThisBinding.ToNumberPrimitive().Value;

    if (double.IsNaN(x))
    {
        return new StringPrimitive("NaN");
    }

    var s = "";

    if (x < 0)
    {
        s = "-";
        x = -x;
    }

    if (double.IsPositiveInfinity(x))
    {
        return new StringPrimitive(s + "Infinity");
    }

    var f = args[0].ToNumberPrimitive().Value;
    if (f < 0D || f > 20D)
    {
        throw new Exception("RangeError");
    }

    var m = "";
    var c = "";
    var d = "";
    var e = 0D;
    var n = 0D;

    if (x == 0D)
    {
        f = 0D;
        m = m.PadLeft((int)(f + 1D), '0');
        e = 0;
    }
    else
    {
        if (!args[0].IsUndefined) // fractionDigits is supplied
        {
            var lower = (int)Math.Pow(10, f);
            var upper = (int)Math.Pow(10, f + 1D);
            var min = 0 - 0.0001;
            var max = 0 + 0.0001; 

            for (int i = lower; i < upper; i++)
            {
                for (int j = (int)f;; --j)
                {
                    var result = i * Math.Pow(10, j - f) - x;
                    if (result > min && result < max)
                    {
                        n = i;
                        e = j;
                        goto Complete;
                    }
                    if (result <= 0)
                    {
                        break;
                    }
                }

                for (int j = (int)f + 1; ; j++)
                {
                    var result = i * Math.Pow(10, j - f) - x;
                    if (result > min && result < max)
                    {
                        n = i;
                        e = j;
                        goto Complete;
                    }
                    if (result >= 0)
                    {
                        break;
                    }
                }
            }
        }
        else
        {
            var min = x - 0.0001;
            var max = x + 0.0001; 

            // Scan for f where f >= 0
            for (int i = 0;; i++)
            {
                // 10 ^ f <= n < 10 ^ (f + 1)
                var lower = (int)Math.Pow(10, i);
                var upper = (int)Math.Pow(10, i + 1D);
                for (int j = lower; j < upper; j++)
                {
                    // n is not divisible by 10
                    if (j % 10 == 0)
                    {
                        continue;
                    }

                    // n must have f + 1 digits
                    var digits = 0;
                    var state = j;
                    while (state > 0)
                    {
                        state /= 10;
                        digits++;
                    }
                    if (digits != i + 1)
                    {
                        continue;
                    }

                    // Scan for e in both directions
                    for (int k = (int)i; ; --k)
                    {
                        var result = j * Math.Pow(10, k - i);
                        if (result > min && result < max)
                        {
                            f = i;
                            n = j;
                            e = k;
                            goto Complete;
                        }
                        if (result <= i)
                        {
                            break;
                        }
                    }
                    for (int k = (int)i + 1; ; k++)
                    {
                        var result = i * Math.Pow(10, k - i);
                        if (result > min && result < max)
                        {
                            f = i;
                            n = j;
                            e = k;
                            goto Complete;
                        }
                        if (result >= i)
                        {
                            break;
                        }
                    }
                }
            }
        }

    Complete:

        m = n.ToString("G");
    }

    if (f != 0D)
    {
        m = m[0] + "." + m.Substring(1);
    }

    if (e == 0D)
    {
        c = "+";
        d = "0";
    }
    else
    {
        if (e > 0D)
        {
            c = "+";
        }
        else
        {
            c = "-";
            e = -e;
        }
        d = e.ToString("G");
    }

    m = m + "e" + c + d;
    return new StringPrimitive(s + m);
}
class Program
{
    // Calculate (20!) 1 million times using both methods.
    static void Main(string[] args)
    {
        Stopwatch sw = Stopwatch.StartNew();
        Int64 result = 0;
        for (int i = 0; i < 1000000; i++)
            result += FactR(20);
        Console.WriteLine("Recursive Time: " + sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        result = 0;
        for (int i = 0; i < 1000000; i++)
            result += FactG(20);
        Console.WriteLine("Goto Time: " + sw.ElapsedMilliseconds);
        Console.ReadLine();
    }

    // Recursive Factorial
    static Int64 FactR(Int64 i)
    {
        if (i <= 1)
            return 1;
        return i * FactR(i - 1);
    }

    // Recursive Factorial (using GOTO)
    static Int64 FactG(Int64 i)
    {
        Int64 result = 1;

    Loop:
        if (i <= 1)
            return result;

        result *= i;
        i--;
        goto Loop;
    }
 Recursive Time: 820
 Goto Time: 259