Есть ли причина использовать goto в современном .NET-коде? - PullRequest
31 голосов
/ 30 марта 2010

Я только что нашел этот код в отражателе в базовых библиотеках .NET ...

    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 из-за страха изгнания в ад на вечность". Я всегда относился к кодировщикам MS с большим уважением, и хотя я, возможно, не соглашался со всеми их решениями, я всегда уважал их рассуждения.

Итак, есть ли веская причина для такого кода, который я пропускаю? Был ли этот фрагмент кода собран неумелым разработчиком? или .NET отражатель возвращает неточный код?

Я надеюсь, что - это хорошая причина, и я просто слепо скучаю по ней.

Спасибо за всеобщее мнение

Ответы [ 19 ]

44 голосов
/ 30 марта 2010

Отражатель не идеален. Фактический код этого метода доступен из справочного источника. Он находится в 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. Он почти наверняка отключен блоками try / catch внутри операторов if ().

Очевидно, что вы захотите отдать предпочтение фактическому исходному коду вместо декомпилированной версии. Сами по себе комментарии весьма полезны, и вы можете рассчитывать на точность источника. Ну, по большей части, есть небольшое повреждение от ошибочного инструмента постобработки, который убрал имена программистов Microsoft. Идентификаторы иногда заменяются тире, а код повторяется дважды. Вы можете скачать исходный код здесь .

12 голосов
/ 30 марта 2010

Я видел, как goto использовался для выхода из вложенных циклов:

Как мне выйти из двух вложенных циклов в Objective-C?не вижу в этом ничего плохого.

12 голосов
/ 30 марта 2010

Его, вероятно, нет в исходном коде, просто выглядит дизассемблированный код.

11 голосов
/ 02 июля 2010

Существует несколько допустимых вариантов использования goto в .NET (в частности, C #):

Симуляция аварийного переключения оператора имитации переключения .

Те, что происходят из фона C ++используются для написания операторов switch, которые автоматически переходят от случая к случаю, если явно не завершены с помощью break.Для C # только тривиальные (пустые) падежи.

Например, в C ++

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;
}

В этом коде C ++ вывод:

Case 1
Case 2
Default Case

Вот аналогичный код C #:

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

Добавление операторов goto заставляет его работать:

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;
}

... другое полезное использование goto в C # - это ...

Бесконечные циклы и развернутая рекурсия

Здесь я не буду вдаваться в подробности, поскольку это менее полезно, но иногда мы пишем бесконечные циклы, используя конструкции while(true), которые явнозавершается break или повторно выполняется с оператором continue.Это может произойти, когда мы пытаемся смоделировать вызовы рекурсивных методов, но не имеем никакого контроля над потенциальной областью действия рекурсии.

Очевидно, что вы можете преобразовать это в цикл while(true) или преобразовать его в отдельныйметод, но также использование метки и оператора goto работает.

Такое использование goto является более спорным, но все же стоит помнить о нем как об одном из вариантов в очень редких случаях.

8 голосов
/ 30 марта 2010

Я не без ума от gotos, но говорить, что они никогда не действительны, глупо.

Я использовал один раз, чтобы исправить дефект в особенно грязном куске кода. Реорганизовать код и протестировать его было бы непрактично, учитывая временные ограничения.

Кроме того, разве мы не видели условные конструкции, которые были настолько плохо закодированы, что они заставляют gotos казаться доброкачественными?

4 голосов
/ 30 марта 2010

Ты не должен смотреть на код рефлектора.

Хотя, если вы когда-нибудь посмотрите на разобранный ИЛ, вы увидите повсюду повсюду. По сути, все циклы и другие используемые нами управляющие конструкции в любом случае преобразуются в gotos, просто превращая их в конструкции в нашем коде, они становятся более читабельными и их легче поддерживать.

Я не думаю, что код, который вы разместили, был бы хорошим местом для использования goto, кстати, и я изо всех сил пытаюсь придумать один.

4 голосов
/ 02 июля 2010

Вы можете использовать GOTO для выполнения рекурсии с лучшей производительностью. Поддерживать его намного сложнее, но если вам нужны эти дополнительные циклы, вы, возможно, захотите оплатить бремя обслуживания.

Вот простой пример с результатами:

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
3 голосов
/ 30 марта 2010

Я не видел действительного случая для Goto во многих, многих строках кода .NET, как написанных, так и проверенных.

В языках, которые не поддерживают обработку структурированных исключений с помощью блока finally (PASCAL - дедушка языков структурированного программирования, а также классического C), тактическое использование GOTO может значительно облегчить понимание кода, когда используется для выполнения очистки, когда выполнение прекращается внутри вложенных циклов (в отличие от правильной установки условий завершения нескольких циклов). Даже в те дни я не использовал goto лично по этой причине (вероятно, из-за страха «вечного изгнания в ад»).

3 голосов
/ 30 марта 2010

Goto часто используются при написании парсеров и лексеров.

2 голосов
/ 30 марта 2010

Нет, нет веских оснований для использования goto. Последний раз я кодировал оператор goto в 1981 году, и с тех пор я не пропустил этот конкретный конструкт.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...