2

データベースに一連のレコードを作成し、問題が発生した場合はすべてをロールバックする必要があるプロセスがあります。私がやりたいことはこれです:

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 ステートメントの適切な使用法ですか、それとも本当に悪い設計ですか? よりエレガントなソリューションはありますか?うまくいけば、このサンプルは要点を伝えることができます

4

16 に答える 16

13

あなたが尋ねなければならないなら、それをしないでください。

特定のコードについては、次のようにすることができます。

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
于 2009-02-19T21:58:16.617 に答える
6

Goto は非常に評判が悪いため、他の開発者はすぐにあなたのコードをよく思わなくなります。goto を使用することが最良の設計上の選択であることを実証できたとしても、コードを見た人に何度も何度も説明する必要があります。

あなた自身の評判のために、それをしないでください。

于 2009-02-19T22:10:09.320 に答える
5

本当にデザインが悪い。はい。

于 2009-02-19T22:00:03.150 に答える
2

適用可能な極端なエッジケースがいくつかあるかもしれませんが、ほとんど明確に、いいえ、使用しないでください。

この特定のケースでは、Using ステートメントを使用して、これをより適切に処理する必要があります。一般に、IDisposable を実装する (または既に実装しているクラスを使用する) クラスを作成し、Dispose メソッドでクリーンアップを処理します。この場合、データベースへの接続を閉じます (明らかに、設計から再び開かれます)。

また、ここでも TransactionScope クラスを使用することをお勧めします。これを使用して、トランザクションのスコープを設定し、コミットしたり、例外が発生した場合に自動中止したりできます。

于 2009-02-19T22:02:04.317 に答える
2

goto を使用する必要があるのは、他に選択肢がない場合だけです。

他に選択肢がないかどうかを確認する唯一の方法は、すべてを試すことです。

あなたの特定の例では、このように代わりに try...finally を使用する必要があります (申し訳ありませんが、私は C# しか知りません)。

void DoStuff()
{
    Connection connection = new Connection();
    try
    {
        connection.Open()
        if( SomethingBadHappened )
            return;
    }
    finally
    {
        connection.Close();
    }    
}
于 2009-02-19T22:06:00.080 に答える
1

私はいつも特定の場所で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

私はそれらを関数の代わりに使用せず、長いコードの非常に大きなブロックを作成します。それらが本当に役立つ小さな場所で、ほとんどの場合、物事をスキップします。

于 2010-12-11T01:10:17.823 に答える
1

Goto は単なる実装の詳細です。try/catch は goto (スタック間の goto です!) によく似ています。必要に応じて、while ループ (または任意の構造) を goto で記述できます。break ステートメントと Early return ステートメントは、それらすべての中で最も薄く偽装された goto です。

したがって、技術的には、それらに実際に問題はありませんが、より困難なコードになります。ループ構造を使用すると、中括弧の領域に拘束されます。探したり、交差したり、実際にどこに行くのか不思議ではありません。

その上、彼らは本当に悪い担当者を持っています. 1 つを使用することを決定した場合、可能な限り最善の場合でも、コードを読み取るすべての人に対してその決定を弁護する必要があります。自分自身で判断を下すため、悪いコードをあちこちで助長しています。

あなたの場合の1つの解決策は、早期リターンがgotoと同じであるという事実を使用することです(ps。これまでで最悪の疑似コード):

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がデータベースをコードの構造に非常に密接にバインドする傾向があることは知っています。さもなければ、これが機能しない可能性さえ考えません...

于 2009-02-19T22:24:18.863 に答える
1

私は非常に控えめに言うでしょう。GOTO ステートメントの使用について考えなければならないときはいつでも、コードのリファクタリングを試みます。私が考えることができる唯一の例外は、ステートメント On Error Goto を含む vb でした。

于 2009-02-19T21:59:25.103 に答える
1

goto に本質的な問題はありませんが、これはあまり理想的な使い方ではありません。例外の定義について、あなたはあまりにも細かい点を指摘していると思います。

カスタム例外をスローして、そこにロールバック コードを配置するだけです。REAL 例外が発生した場合は、とにかくロールバックしたいと思うので、その方法でも二重の義務を負います。

于 2009-02-19T22:02:23.003 に答える
0

誰もがそれを避けると言いますが、なぜですか。GOTO 構文は、アセンブリのジャンプ ステートメントです。非常に効率的です。

それを避ける主な理由は、コードの読みやすさです。目で確認するのが難しいコード内の GOTO ラベルを見つける必要があります。

メモリ リークが発生する可能性があると考える人もいますが、.NET ではそうではないと専門家が言うのを見てきました。

于 2016-06-02T17:39:49.770 に答える
0

go to ステートメントは、プログラムの流れを理解しにくくする傾向があります。Visual Basic 6 と「on error」の組み合わせを除いて、過去 10 年間に使用したことを思い出せません。

プログラム フローが非常に明確であるため、go to の使用は、私に関する限り許容されます。try ... catch を使用しても状況が大幅に改善されるとは思いません。なぜなら、go tos が現在ある場所で例外をスローする必要があるからです。

ただし、フォーマットはあまり魅力的ではありません:-)

go to ラベルの名前を別の名前に変更します。これは、すべてが成功したときにこの場所にも到達するためです。clean_up: いいですね。

于 2009-02-19T22:14:21.040 に答える
0

ええ、VBscript/ASP でエラーを処理するために適切に使用されていました。on error resume next の使用が終了したら、エラー処理を ASP に戻すために使用しました。

.netで?天国、いいえ!

于 2009-02-19T22:20:26.097 に答える
0

goto が使用されているのを見るたびに、単純なリファクタリングで処理できたはずです。使用する必要があることを「知っている」場合を除き、使用しないことをお勧めします

于 2009-02-19T22:02:27.730 に答える
0

絶対にないと言いたくなるのですが、それが最善の解決策になる場合は常に 1 つあると思います。しかし、私は過去 20 年ほどの間、Goto ステートメントを使用せずにプログラミングを行ってきました。

于 2009-02-19T22:02:41.523 に答える
0

各関数呼び出しを try catch ブロックでラップしないのはなぜですか。それが完了すると、例外の 1 つがスローされた場合、それをキャッチして接続を閉じることができます。このようにして、GOTO ステートメントを完全に回避します。

要するに、GOTO ステートメントは、異常な状況を除いて、良いことではなく、通常、それを避けるためにリファクタリングする必要があります。これは初期の言語 (この場合は BASIC) の名残であることを忘れないでください。

于 2009-02-19T22:04:03.797 に答える
0

一般にスパゲッティ コードの導入に関連するものであるため、使用は非常に慎重に行う必要があります。ラベルの代わりにメソッドを使用してみてください。

GOTO を使用する良いケースは、VB ではなく C# で使用できる select を介したフローを作成することです。

于 2009-02-19T22:07:05.787 に答える