14

私は現在この問題を抱えていませんが、あなたは決して知りませんし、思考実験は常に楽しいものです.

これを試みるためにアーキテクチャで発生する明らかな問題を無視して、誰かが設計した恐ろしく書かれたコードがあり、同じコードで多種多様な操作を実行する必要があると仮定しましょう。ブロック、例:

WidgetMaker.SetAlignment(57);
contactForm["Title"] = txtTitle.Text;
Casserole.Season(true, false);
((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true;

100 倍します。これらのいくつかはうまくいくかもしれませんが、他のものはひどくうまくいかないかもしれません. 必要なのは、"on error resume next" に相当する C# です。そうしないと、多くのコード行で try-catch をコピー アンド ペーストすることになります。

この問題にどのように取り組もうとしますか?

4

19 に答える 19

46
public delegate void VoidDelegate();

public static class Utils
{
  public static void Try(VoidDelegate v) {
    try {
      v();
    }
    catch {}
  }
}

Utils.Try( () => WidgetMaker.SetAlignment(57) );
Utils.Try( () => contactForm["Title"] = txtTitle.Text );
Utils.Try( () => Casserole.Season(true, false) );
Utils.Try( () => ((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true );
于 2008-09-22T21:24:51.823 に答える
22

個々の名前の付いたメソッドにリファクタリングします。

AdjustFormWidgets();
SetContactTitle(txtTitle.Text);
SeasonCasserole();

それらのそれぞれは適切に保護されています。

于 2008-09-22T20:04:27.257 に答える
19

私は何もしないと言うでしょう。

そうです、何もしないでください。

あなたは私に2つのことを明確に特定しました:

  1. あなたはアーキテクチャが壊れていることを知っています。
  2. このがらくたがたくさんあります。

私は言う:

  • 何もしない。
  • グローバルエラーハンドラーを追加して、ブームになるたびに電子メールを送信します。
  • 何かが倒れる (またはテストに失敗する) まで待ちます
  • それを修正します(ページの範囲内で必要に応じてリファクタリングします)。
  • 問題が発生するたびに繰り返します。

そんなにひどい場合は、すぐに解決できます。うん、うんざりするように聞こえるし、そもそもバグ修正で髪を引っ張っているかもしれないが、実際に動作している可能性のある(大量の)コードの前に、必要な/バグのあるコードを修正することができます見えます。

戦争に勝利し始めると、(すべてのリファクタリングにより) コードをより適切に処理できるようになり、そのための勝利の設計についてより良いアイデアが得られます..

すべてをプチプチで包み込もうとすると、おそらく時間がかかり、問題を解決することはできません。

于 2008-09-22T21:24:02.073 に答える
12

実際にOnErrorResume Nextが含まれているVB.NETでコードを記述し、それをDLLでC#にエクスポートすることは非常に明白です。他のものはただ罰のための大食いです。

于 2008-09-22T21:54:04.453 に答える
9

フェイルファスト

詳しく言うと、私は質問に疑問を抱いていると思います。例外がスローされた場合、何も起こらなかったかのようにコードを単純に続行したいのはなぜですか? 特定の状況で例外が予想される場合は、そのコードの周りに try-catch ブロックを記述して処理します。または、予期しないエラーが発生した場合は、アプリケーションを中止、再試行、または失敗することを優先する必要があります。「頭脳」をうめく負傷したゾンビのように続けてはいけません。

于 2008-09-22T20:20:45.113 に答える
8

これは、プリプロセッサがあると便利なことの 1 つです。例外を飲み込むマクロを定義してから、簡単なスクリプトでそのマクロをすべての行に追加できます。

したがって、これが C++ の場合、次のようにすることができます。

#define ATTEMPT(x) try { x; } catch (...) { }
// ...
ATTEMPT(WidgetMaker.SetAlignment(57));
ATTEMPT(contactForm["Title"] = txtTitle.Text);
ATTEMPT(Casserole.Season(true, false));
ATTEMPT(((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true);

残念ながら、C/C++ のようにプリプロセッサを含む言語は多くないようです。

独自のプリプロセッサを作成し、ビルド前のステップとして追加できます。完全に自動化したい場合は、おそらく実際のコード ファイルを取得し、try/catch のものを独自に追加するプリプロセッサを作成できます (したがって、これらの ATTEMPT() ブロックを手動でコードに追加する必要はありません)。 . ただし、想定されている行のみが変更されていることを確認するのは難しい場合があります(ビルドを壊さないように、変数宣言、ループ構成などをスキップする必要があります)。

しかし、これらは恐ろしい考えであり、決して行うべきではないと思いますが、質問がありました. :)

本当に、これを行うべきではありません。エラーの原因を見つけて修正する必要があります。エラーを飲み込む/無視するのは悪いことなので、ここでの正解は「バグを修正し、無視しないでください!」だと思います。:)

于 2008-09-22T20:08:34.610 に答える
7

On Error Resume NextC# の世界では本当に悪い考えです。On Error Resume Next実際にあなたを助けるために同等のものを追加することもありません。それが行うことは、より微妙なエラー、データの損失、および場合によってはデータの破損を引き起こす可能性のある悪い状態のままにすることだけです.

しかし、質問者に正当な理由を与えるために、グローバル ハンドラーを追加し、TargetSite をチェックして、どのメソッドが中断したかを確認することができます。そうすれば、少なくともそれがどのラインで始まったかを知ることができます. 次の部分は、デバッガーと同じ方法で「次のステートメント」を設定する方法を試して理解することです。この時点でスタックが巻き戻されていないか、再作成できることを願っていますが、試してみる価値は確かにあります。ただし、このアプローチでは、コードを毎回デバッグ モードで実行して、デバッグ シンボルを含める必要があります。

于 2008-09-22T20:01:14.007 に答える
4

誰かが言ったように、VB はこれを許可します。C#でも同じようにしたらどうですか?信頼できるリフレクターを入力してください:

これ:

Sub Main()
    On Error Resume Next

    Dim i As Integer = 0

    Dim y As Integer = CInt(5 / i)


End Sub

これに変換します:

public static void Main()
{
    // This item is obfuscated and can not be translated.
    int VB$ResumeTarget;
    try
    {
        int VB$CurrentStatement;
    Label_0001:
        ProjectData.ClearProjectError();
        int VB$ActiveHandler = -2;
    Label_0009:
        VB$CurrentStatement = 2;
        int i = 0;
    Label_000E:
        VB$CurrentStatement = 3;
        int y = (int) Math.Round((double) (5.0 / ((double) i)));
        goto Label_008F;
    Label_0029:
        VB$ResumeTarget = 0;
        switch ((VB$ResumeTarget + 1))
        {
            case 1:
                goto Label_0001;

            case 2:
                goto Label_0009;

            case 3:
                goto Label_000E;

            case 4:
                goto Label_008F;

            default:
                goto Label_0084;
        }
    Label_0049:
        VB$ResumeTarget = VB$CurrentStatement;
        switch (((VB$ActiveHandler > -2) ? VB$ActiveHandler : 1))
        {
            case 0:
                goto Label_0084;

            case 1:
                goto Label_0029;
        }
    }
    catch (object obj1) when (?)
    {
        ProjectData.SetProjectError((Exception) obj1);
        goto Label_0049;
    }
Label_0084:
    throw ProjectData.CreateProjectError(-2146828237);
Label_008F:
    if (VB$ResumeTarget != 0)
    {
        ProjectData.ClearProjectError();
    }
}
于 2008-09-23T02:03:23.400 に答える
3

コードを書き直します。論理的に相互に依存するステートメントのセットを見つけて、1つが失敗した場合に次のステートメントが意味をなさないようにし、それらを独自の関数に隠して、トライキャッチを配置します。それと続行します。

于 2008-09-22T20:03:52.283 に答える
2

これは、最も問題のある部分を特定するのに役立ちます。

@ JB King 思い出させてくれてありがとう。Logging アプリケーション ブロックには、イベントのトレースに使用できる Instrumentation Event があります。詳細については、MS Enterprise ライブラリのドキュメントを参照してください。

Using (New InstEvent)
<series of statements> 
End Using

この使用のすべてのステップはログ ファイルにトレースされ、それを解析して、ログが壊れている場所 (ex がスローされた場所) を確認し、重大な違反者を特定できます。

リファクタリングが最善の策ですが、リファクタリングが多い場合は、最悪の違反者を特定するのに役立つ場合があります。

于 2008-09-22T20:23:00.660 に答える
1

コンパイラにこのコードの式ツリーを提供させることができる場合は、各ステートメントを元のステートメントをラップする新しいtry-catchブロックに置き換えることで、その式ツリーを変更できます。これは、思ったほど大げさではありません。LINQの場合、C#は、実行時にユーザーコードで操作できる式ツリーとしてラムダ式をキャプチャする機能を取得しました。

このアプローチは、今日の.NET3.5では不可能です。System.Linq.Expressionsに「try」ステートメントがない以外の理由がない場合です。ただし、DLR式ツリーとLINQ式ツリーのマージが完了すると、C#の将来のバージョンで実行可能になる可能性があります。

于 2008-09-22T20:06:39.670 に答える
1

C#でリフレクションを使用してみませんか?コードを反映するクラスを作成し、個々のtry/catchブロックに何を入れるかについてのヒントとして行番号を使用できます。これにはいくつかの利点があります。

  1. ソースコードを壊す必要がなく、デバッグモードでのみ使用できるため、少し醜くありません。
  2. 実装中にc#について何か面白いことを学びます。

ただし、もちろん、一部の作業の保守を引き継いでいて、例外を修正できるように例外を処理する必要がある場合を除いて、これには反対することをお勧めします。でも書くのは楽しいかもしれません。

于 2008-09-23T02:16:56.193 に答える
1

goto を使用できますが、それでも面倒です。

私は実際には、しばらくの間、ある種の単一ステートメントの try-catch が欲しかったのです。ロギング コードを追加したり、失敗した場合にメイン プログラム フローを中断したくないものを追加したりするなど、特定の場合に役立ちます。

linq に関連する機能のいくつかで何かできるのではないかと思いますが、現時点ではそれを調べる時間がありません。ステートメントを匿名関数としてラップする方法を見つけることができれば、try-catch ブロック内で別の関数を使用してそれを呼び出すことができますが、それが可能かどうかはまだわかりません。

于 2008-09-22T20:18:54.710 に答える
1

アプリケーションのUnhandledException イベントでエラーをキャッチします。そうすれば、未処理の例外を、送信者や、開発者が妥当と考えるその他の情報としてログに記録することもできます。

于 2011-08-03T15:14:09.030 に答える
1

楽しい質問です。非常にひどい。

マクロを使っていただけると助かります。しかし、これは爆破されたC#であるため、プリプロセッサの作業または外部ツールを使用して、行を個々のtry-catchブロックにラップすることで解決できます。それらを手動でラップしたくないという意味なのか、それとも try-catch を完全に避けたいという意味なのかはわかりません。

これをいじって、すべての行にラベルを付けて、1 つのキャッチからジャンプして戻ろうとしましたが、あまり運がありませんでした。しかし、クリストファーはこれを行う正しい方法を発見しましたDot Net ThoughtsおよびMike Stall の .NET Blogには、これに関する興味深い追加の議論があります。

編集:もちろん。リストされているtry-catch/ソリューションは、ラベルが の範囲外であるswitch-gotoため、実際にはコンパイルされません。このようなものをコンパイルするために何が欠けているか知っている人はいますか?trycatch

コンパイラの前処理ステップでこれを自動化するか、Mike Stall の Inline IL ツールをハックしてエラー無視を挿入することができます。

(例外の調査と次の命令の設定に関する Orion Adrian の回答も興味深いものです。)

全体として、興味深く有益な演習のようです。もちろん、どの時点で ON ERROR RESUME NEXT をシミュレートする労力がコードを修正する労力を上回るかを判断する必要があります。:-)

于 2008-09-23T16:29:49.607 に答える
0

残念ながら、あなたはおそらく運が悪いです。On Error Resume Nextは、一般的に非常に推奨されていないレガシーオプションであり、C#に関する私の知識に相当するものはありません。

コードをVBに残し(OnError ResumeNextに対する特定の要求を考えると、それがソースのようです)、必要な新しいコードを実装するC#dllまたはexeとインターフェイスすることをお勧めします。次に、リファクタリングを実行してコードを安全にし、この安全なコードをC#に変換します。

于 2008-09-22T20:03:00.367 に答える
0

未処理の例外を処理する方法の 1 つのアイデアとして、Enterprise Library の Exception Handling コンポーネントを統合することを検討できます。

これが ASP.Net アプリケーションの場合、Global.asax には「Application_Error」と呼ばれる関数があり、ほとんどの場合、壊滅的な障害が通常は別のケースとして呼び出されます。

于 2008-09-22T20:11:18.303 に答える
-1

これを避けたいと思うすべての理由を無視する.......

単に行数を抑える必要がある場合は、次のようなものを試すことができます。

int totalMethodCount = xxx;
for(int カウンター = 0; カウンター < totalMethodCount; カウンター++) {
    試す {
        if (カウンター == 0) WidgetMaker.SetAlignment(57);
        if (カウンター == 1) contactForm["タイトル"] = txtTitle.Text;
        if (counter == 2) Casserole.Season(true, false);
        if (counter == 3) ((RecordKeeper)Session["CasseroleTracker"]).Seasoned = true;
    } catch (例外例) {
        //ここにログイン
    }
}

ただし、呼び出しの結果を再利用しようとする場合は、変数のスコープに注意する必要があります。

于 2008-09-22T20:07:56.047 に答える
-7

各行を一度に1つずつハイライトし、「Surroundwith」try/catchを実行します。それはあなたが言及したコピー貼り付けを回避します

于 2008-09-22T20:04:12.813 に答える