Когда можно использовать оператор GoTo в VB.Net? - PullRequest
3 голосов
/ 20 февраля 2009

У меня есть процесс, который должен создать кучу записей в базе данных и откатить все назад, если что-то пойдет не так. Что я хочу сделать, это:

Public Structure Result
    Public Success as Boolean
    Public Message as String
End Structure

Private _Repository as IEntityRepository

Public Function SaveOrganization( _
    ByVal organization As rv_o_Organization) As Result
    Dim result = Result.Empty

    _Repository.Connection.Open()
    _Repository.Transaction = _Repository.Connection.BeginTransaction()

    ''//Performs validation then saves it to the database
    ''// using the current transaction
    result = SaveMasterOrganization(organization.MasterOrganization)
    If (Not result.Success) Then
        GoTo somethingBadHappenedButNotAnException
    End If

    ''//Performs validation then saves it to the database
    ''//using the current transaction
    result = SaveOrganziation(dbOrg, organization)
    If (Not result.Success) Then GoTo somethingBadHappenedButNotAnException

somethingBadHappenedButNotAnException:
    _Repository.Transaction.Commit()
    _Repository.Connection.Close()
    Return result
End Sub

Это правильное использование оператора GoTo или просто очень плохой дизайн? Есть ли более элегантное решение? Надеюсь, что этот образец сможет получить точку через

Ответы [ 16 ]

13 голосов
/ 20 февраля 2009

Если вам нужно спросить, не делайте этого.

Для вашего конкретного кода вы можете сделать это так:

Public Function SaveOrganization(ByVal organization As rv_o_Organization) As Result
    Dim result As Result = Result.Empty

    _Repository.Connection.Open()
    _Repository.Transaction = _Repository.Connection.BeginTransaction()

    'Performs validation then saves it to the database 
    'using the current transaction
    result = SaveMasterOrganization(organization.MasterOrganization)

    'Performs validation then saves it to the database 
    'using the current transaction
    If result.Success Then result = SaveOrganziation(dbOrg, organization)

    _Repository.Transaction.Commit()
    _Repository.Connection.Close()
    Return result
End Sub
6 голосов
/ 20 февраля 2009

Goto имеет такую ​​ужасную репутацию, что заставит других разработчиков моментально задуматься о вашем коде. Даже если вы сможете продемонстрировать, что использование goto было лучшим выбором для разработки - вам придется объяснять это снова и снова всем, кто видит ваш код.

Ради собственной репутации, просто не делайте этого.

6 голосов
/ 20 февраля 2009

Действительно плохой дизайн. Да.

2 голосов
/ 20 февраля 2009

Единственный раз, когда вы должны использовать goto, это когда нет другой альтернативы.

Единственный способ выяснить, нет ли других альтернатив, - это попробовать их все.

В вашем конкретном примере вы должны использовать try ... finally вместо этого, как это (извините, я знаю только C #)

void DoStuff()
{
    Connection connection = new Connection();
    try
    {
        connection.Open()
        if( SomethingBadHappened )
            return;
    }
    finally
    {
        connection.Close();
    }    
}
2 голосов
/ 20 февраля 2009

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

В этом конкретном случае вы должны использовать оператор Using, чтобы лучше справиться с этим. Как правило, вы создаете класс, который будет реализовывать IDisposable (или использовать тот, который уже делает), а затем обрабатывать очистку в методе Dispose. В этом случае вы бы закрыли соединение с базой данных (по-видимому, оно снова открывается из вашего проекта).

Кроме того, я бы также предложил использовать здесь класс TransactionScope, который можно использовать для определения объема транзакции, а затем для ее фиксации, а также для автоматического прерывания перед лицом исключений.

1 голос
/ 11 декабря 2010

Я все время использую goto в определенных местах, например, прямо над Try Catch, если вы запрашиваете у пользователя «Повторить? Отмена», если повтор, Goto StartMyTask: и увеличиваете текущую попытку Максимальных попыток в зависимости от сценария.

Они также удобны для каждой петли.

For each Items in MyList

 If VaidationCheck1(Item) = false then goto SkipLine
 If ValidationCheck(Item) = false then goto skipline

 'Do some logic here, that can be avoided by skipping it to get better performance.
 'I use then like short circuit operands, why evaluate more than you actually have to?

 SkipLine:
Next

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

1 голос
/ 20 февраля 2009

Gotos - это просто деталь реализации. Try / catch очень похож на goto (в данном случае это goto между стеками!). Цикл while (или любая конструкция) может быть записан с помощью gotos, если хотите. Заявления о разрыве и досрочном возврате являются наиболее тонко замаскированными gotos из всех - они явные (и некоторые люди не любят их из-за сходства)

Так что технически в них нет ничего неправильного, но они создают более сложный код. Когда вы используете циклические структуры, вы привязаны к области ваших фигурных скобок. Не удивительно, куда вы на самом деле собираетесь, ищите или пересекаете.

Кроме того, у них есть ДЕЙСТВИТЕЛЬНО ПЛОХОЙ представитель. Если вы решите использовать его, даже в лучшем из возможных случаев, вам придется защищать свое решение от всех, кто когда-либо читает ваш код - и многие из тех людей, от которых вы будете защищаться, не будут иметь возможности чтобы сделать суждение называть себя, так что вы поощряете плохой код вокруг.

Одним из решений для вашего случая может быть использование того факта, что ранний возврат - это то же самое, что и goto (пс. Худший из когда-либо существовавших psuedocode):

dbMethod() {
    start transaction
    if(doWriteWorks())
        end Transaction success
    else
        rollback transaction
}
doWriteWorks() {
    validate crap
    try Write crap
    if Fail
        return false
    validate other crap
    try Write other crap
    if Fail
        return false
    return true
}

Я думаю, что этот шаблон будет работать в VB, но я не использовал его с VB 3 (примерно в то время, когда его купил MS), поэтому, если транзакции каким-то образом связаны с контекстом исполняемого метода или чем-то еще, я не знаю. Я знаю, что MS имеет тенденцию очень тесно связывать базу данных со структурой кода, иначе я бы даже не подумал, что это не работает ...

1 голос
/ 20 февраля 2009

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

Просто добавьте пользовательское исключение и вставьте туда свой код отката. Я предполагаю, что вы также захотите откатить в любом случае, если возникнет РЕАЛЬНОЕ исключение, так что вы получите двойную обязанность и в этом случае.

1 голос
/ 20 февраля 2009

Я бы сказал очень экономно. В любое время, когда мне приходилось думать об использовании оператора GOTO, я пытаюсь реорганизовать код. Единственное исключение, о котором я могу думать, было в vb с оператором On Error Goto.

0 голосов
/ 02 июня 2016

Все говорят, избегайте этого, но почему. Синтаксис GOTO - это оператор перехода в сборке - очень эффективный.

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

Некоторые люди думают, что это может вызвать утечки памяти, но я видел, что эксперты говорят, что это не так в .NET.

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