C#の「エラー履歴書の次へ」の最良の代替案は何ですか?
-
26-10-2019 - |
質問
C#コードに空のキャッチブロックを入れた場合、VB.NETの「On Error Resume Next」ステートメントに相当するものになります。
try
{
C# code;
}
catch(exception)
{
}
私がこれを尋ねている理由は、VB.NETコードをC#に変換する必要があり、古いコードにはエラー履歴書が次の「次の」ステートメントが〜200 "あるためです。 try {} catch {}
私の新しいコードには、より良い代替手段がありますか?
解決
VBプログラマーはしばしば多くのコードを散らばっていることがわかりました On Error Resume Next
(悪い)習慣からの声明。私の提案は始めることです 番号 例外を抑制し、実際に壊れるものを確認します。あなたが思うほど多くの問題はないかもしれません。逆に、より多くの回帰テストができるほど良いです。エラーが無視された場合にのみ機能するエッジケースがいくつかあります。
最終的には、多くのTry/Catchブロック内での優雅な巻き戻しであろうと、エラーがトップレベルのハンドラーにエラーを浸透させるかどうかにかかわらず、エラー処理戦略を決定する必要があります(両方の戦略には用途があります)。
締め切りを満たすためにいくつかの例外を抑制しなければならない場合は、 少なくとも これらの例外を記録して、コードで作業する次の開発者が空で燃やされないようにします try/catch
.
他のヒント
これは許容されることもありますが、一般にコードの臭いを示します。発生した例外を飲み込みたいと思うと確信している場合は、あなたが持っている方法でそれを行うことができますが、一般的に例外がスローされている場合 したほうがいい 行う なにか.
通常、適切に設計されたコードで同じ結果を達成できます。現在、特定のエラーが発生している場合は、質問に追加してください。ただし、好奇心からだけ求めている場合は、同等のものはありません。それは良いことです。
いいえ、それは同じではありません。
次にエラー履歴書を使用すると、VBはエラーが発生した場合に次の行にスキップします。 Try/Catchを使用すると、エラー(例外)が発生した場合、実行はキャッチブロックにジャンプします。
分析する必要があります On Error Resume Next
ステートメントを1つずつ見て、その目的が何であるかを確認します。いくつかはずさんなコードであるかもしれませんが、正当な理由があります On Error Resume Next
Visual Basic 6.0コードで。
使用する理由のいくつかの例 On Error Resume Next
Visual Basic 6.0コード:
視覚的な基本6.0コレクションに特定のキーが存在するかどうかを確認します。これを行う唯一の方法は、キーごとに要素にアクセスし、キーが存在しない場合に発生するエラーを処理することです。 .NETに変換する場合、これをキーの存在のチェックに置き換えることができます。
文字列を整数に解析します。 .NETで使用できます TryParse.
それでも On Error Resume Next
確かに合法的に使用されている以上に乱用されていることは、VB.NETでも役立つ場所があります。
すべてのプリンターパラメーターにデフォルトなど、多数のExcelプロパティに値を割り当てるプログラムを検討してください。Excelには無数のプリンターパラメーターがあります。 Excelの後のバージョンには、以前のバージョンがサポートされていないプロパティがあり、各バージョンでサポートされているものを把握することは些細なことではありません。プロパティが存在する場合、プログラムは値を割り当てる必要がありますが、Excelの古いバージョンが使用されている場合はプロパティを無視します。
VB.NETでこれを行う「正しい」方法は、Excelの各バージョンでサポートされているプリンタープロパティを決定し、使用中のバージョンを読み取り、そのバージョンで実装されているプロパティのみに割り当てることです。それには、多くの研究といくつかのコードが必要であり、すべてがほとんど利益をもたらす必要があります。 On Error Resume Next
より実用的な解決策になります。
そして、残念ながら、私は今、まさにこの問題に直面しています。私が試してみようとしている回避策は、エラーを無視して、ある値を別の値に割り当てるだけのサブルーチンを書くことです。各割り当てステートメントの代わりにこのサブルーを呼び出します。あまりにも容易ではありませんが、それほど大きくはありません。
「エラー履歴書の次へ」は、VBでのエキスパートレベルのエラー処理である「インラインエラー処理」を許可します。概念は、エラーごとにエラーを処理するか、エラーに基づいてアクションを実行するか、有益な場合はエラーを無視することですが、コードジャンプを使用しないシーケンスでコードを実行します。
残念ながら、多くの初心者は「エラー履歴書次へ」を使用して、すべてのエラーを無視してアプリケーションを使用している人からの能力の欠如または怠lazのいずれかを隠すために使用しました。 Try/catch
ISブロックレベルエラー処理であり、Pre-.NETの世界では、設計と実装により中級でした。
VB.NETの「On Error Resume Next」の問題は、実行するコードのすべての行にERRオブジェクトをロードするため、したがって、より遅いことです。 try/catch
. 。このフォーラムがチェックされ、エラー履歴書を次に使用することが悪い習慣とコードのごみであると主張する無線の回答をチェックして促進したことに幾分心配しています。これはC#フォーラムです。 C#プログラマーが本当に精通していない別の言語でショットを撮るために使用されるべきですか?
https://msdn.microsoft.com/en-us/library/aa242093(v=vs.60).aspx
実際のVBエクスペリエンスのない中間C#プログラマーは、別の「Microsoft Net」言語に対する奇妙な軽daのために、C#を馬鹿にして限定されたままにしようとするべきではないと言われています。次のコードを検討してください。
//-Pull xml from file and dynamically create a dataset.
string strXML = File.ReadAllText(@"SomeFilePath.xml");
StringReader sr = new StringReader(strXML);
DataSet dsXML = new DataSet();
dsXML.ReadXml(sr);
string str1 = dsXML.Tables["Table1"].Rows[0]["Field1"].ToString();
string str2 = dsXML.Tables["Table2"].Rows[0]["Field2"].ToStrin();
string str3 = dsXML.Tables["Table3"].Rows[0]["Field3"].ToStrin();
string str4 = dsXML.Tables["Table4"].Rows[0]["Field4"].ToString();
string str5 = dsXML.Tables["Table5"].Rows[0]["Field5"].ToString();
XMLに通常Field3の値があるが、そうでない場合。テーブルにフィールドが含まれていないという迷惑なエラーが発生します。データが不要なためではない場合は、気にすることができません。この場合、エラー履歴書の場合、次にエラーを無視するだけで、テーブル、行、列の組み合わせが含まれていることをチェックする変数を設定するコードの各行の周りにコーディングする必要はありません。これは小さな例です。大きなファイルから何千ものテーブル、列、行の組み合わせを取り入れることができます。また、ここで、この方法で文字列変数を入力する必要があると仮定します。これは未処理のコードであり、トラブルが発生します。
VB.NETを検討し、次の実装を再開します。
On Error Resume Next
'Pull Xml from file And dynamically create a dataset.
Dim strXML As String = File.ReadAllText("SomeFilePath.xml")
Dim srXmL As StringReader = New StringReader(strXML)
Dim dsXML As DataSet = New DataSet()
dsXML.ReadXml(srXmL)
'Any error above will kill processing. I can ignore the first two errors and only need to worry about dataset loading the XML.
If Err.Number <> 0 Then
MsgBox(Err.Number & Space(1) & Err.Description)
Exit Sub 'Or Function
End If
Dim str1 As String = dsXML.Tables("Table1").Rows(1)("Field1").ToString()
Dim str2 As String = dsXML.Tables("Table2").Rows(2)("Field2").ToString()
Dim str3 As String = dsXML.Tables("Table3").Rows(3)("Field3").ToString()
Dim str4 As String = dsXML.Tables("Table4").Rows(4)("Field4").ToString()
上記のコードでは、1つの可能なエラー条件を処理する必要がありました。 3番目のエラーが処理される前に2つのエラーがありましたが。次にエラー履歴書のRAD開発のニーズ。 C#は私の言語の選択ですが、多くの理由でVBほどrad言語ではありません。すべてのプログラマーが、いくつかの主要な言語(すなわち、c)が実行され、未処理のエラーで実行を停止しないことを認識していることを願っています。開発者の仕事は、彼らが必要と思われる場所をチェックすることです。エラー履歴書の場合、次はマイクロソフトの世界でそのパラダイムに最も近いものです。
幸いなことに、.NETはこれらの状況に対処するために多くの高度な選択肢を提供しています。私はcontainsを逃れました。したがって、C#では、言語の知識レベルを強化する必要があり、C#言語の仕様によれば、そのような問題を回避する必要があります。迷惑な捨てエラーを含む可能性のあるコードの反復線の大きなブロックを処理するためのソリューションを検討してください。
try
{
if (!File.Exists(@"SomeFilePath.xml")) { throw new Exception("XML File Was Not Found!"); }
string strXML = File.ReadAllText(@"SomeFilePath.xml");
StringReader sr = new StringReader(strXML);
DataSet dsXML = new DataSet();
dsXML.ReadXml(sr);
Func<string, string, int, string> GetFieldValue = (t, f, x) => (dsXML.Tables[t].Columns.Contains(f) && dsXML.Tables[t].Rows.Count >= x + 1) ? dsXML.Tables[t].Rows[x][f].ToString() : "";
//-Load data from dynamically created dataset into strings.
string str1 = GetFieldValue("Table1", "Field1", 0);
string str2 = GetFieldValue("Table2", "Field2", 0);
string str3 = GetFieldValue("Table3", "Field3", 0);
//-And so on.
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
トライ/キャッチブロックでは、ラムダ関数は、XMLによって動的に入力されたデータセットから引き出されているすべてのテーブル、行、列の組み合わせの存在をチェックしています。これは行ごとにチェックされる可能性がありますが、多くの過剰コードが必要になります(ここでは、同じ量の実行コードがありますが、維持するコードがはるかに少ないです)。残念ながら、これは「1つの線機能」の別の悪い慣行と見なされる可能性があります。私は、ラムダと匿名の関数の場合にそのルールを破ります。
.netはオブジェクトのステータスを確認するための非常に多くの方法を提供しているためです。エラーの履歴書は、.NET以前ほどVBの専門家にとってそれほど重要ではありませんが、まだ周りにいるのは素晴らしいことではありません。特に、速くて汚れていない時間の無駄になるものをコーディングしている場合。 JavaはC#に変換します。 Microsoft Worldに参加して、10000中間のJavaとC#プログラマーが言っている場合は、1つのトップレベルのMicrosoft Guru(VB Languageと.NETを作成した人のいずれかなど)が明らかにあなたと矛盾しているため、それは真実であるに違いないとふりをします。 .NET自体の開発、それは間違っており、あなたは愚かに見えます。 C#とVBとF#で取得できるすべての機能、および使用する必要がある他の言語が必要です。 C#はエレガントですが、VBは在職期間がはるかに長いため、VBはより進化しますが、どちらも「同じこと」を行い、同じオブジェクトを使用しています。それらの両方をよく学ぶか、比較会話でコメントすることに抵抗してください。 90年代半ばからMicrosoft Technologiesを高レベルで使用していた私たちにとっては、吐き気がします。
「On Error Resume Next」を使用することは、エラー処理のための良い考えではありません(もちろん、これは私の個人的な意見ですが、ほとんどの開発者は私に同意しているようです)。他の人が以前の投稿でアドバイスしたように、使用してください Try...Catch...Finally
(入るかどうか vb.net またはc#)。
これはエラー処理のための非常にスマートなオプションですが、エラー(空のキャッチブロック)で何もしないこともできます:)すべてのコード(エラーを引き起こす可能性がある)を個別に配置することをお勧めします Try...Catch Block
, 、エラーが発生した場合に何でもする機会があります。ハッピーコーディングみんな:)
「On Error Resume Next」の適切な.NET交換は、Try___メソッドの使用です。 Visual Basic 6.0では、コレクションにキーが存在するかどうかを調べるために、コレクションを手動で検索する(恐ろしく遅い)か、それをインデックスを付けて、そこにない場合に発生したエラーをトラップしようとする必要がありました。 VB.NETでは、辞書オブジェクト(古いコレクションの改良バージョン)がサポートしています TryGetValue
メソッドは、値を成功させる試みが成功したかどうかを示します。他の多くの.NETオブジェクトは、同様の機能をサポートしています。同等の「試してください」が必要な方法はいくつかありますが、そうしないでください(たとえば、 Control.BeginInvoke
)、しかし、それらを個別に包むのに十分なものはほとんどありません Try/Catch
あまりにも面倒ではありません。
「エラーの履歴書で次の履歴書」を発明した人々は、作成したときに何かを念頭に置いていたと思います。あなたの質問に対する答えはノーであるでしょう、C#のこの構成に相当するものは何もありません。私たちはC#と.NETに、ケアと注意に非常に飢えている多くの機能を持っています。ほとんどすべてが例外を投げることができるとき、その単語自体はそれがいくらか意味を失います。あなたは反復の中にあり、数千の100万のアイテムがたまたま例外的である場合、あなたは何をすべきですか?次の履歴書は、便利な答えの1つかもしれません。
@Tim Medoraが言ったように、コーディング時にそのようなアプローチを使用しないように努力する必要があります。ただし、場合によっては有用であり、そのような動作をエミュレートすることが可能です。以下は、それを使用する機能と例です。 (一部のコード要素はC#6を使用して記述されたことに注意してください)
/// <summary>
/// Execute each of the specified action, and if the action is failed, go and executes the next action.
/// </summary>
/// <param name="actions">The actions.</param>
public static void OnErrorResumeNext(params Action[] actions)
{
OnErrorResumeNext(actions: actions, returnExceptions: false);
}
/// <summary>
/// Execute each of the specified action, and if the action is failed go and executes the next action.
/// </summary>
/// <param name="returnExceptions">if set to <c>true</c> return list of exceptions that were thrown by the actions that were executed.</param>
/// <param name="putNullWhenNoExceptionIsThrown">if set to <c>true</c> and <paramref name="returnExceptions"/> is also <c>true</c>, put <c>null</c> value in the returned list of exceptions for each action that did not threw an exception.</param>
/// <param name="actions">The actions.</param>
/// <returns>List of exceptions that were thrown when executing the actions.</returns>
/// <remarks>
/// If you set <paramref name="returnExceptions"/> to <c>true</c>, it is possible to get exception thrown when trying to add exception to the list.
/// Note that this exception is not handled!
/// </remarks>
public static Exception[] OnErrorResumeNext(bool returnExceptions = false, bool putNullWhenNoExceptionIsThrown = false, params Action[] actions)
{
var exceptions = returnExceptions ? new Collections.GenericArrayList<Exception>() : null;
foreach (var action in actions)
{
Exception exp = null;
try { action.Invoke(); }
catch (Exception ex) { if(returnExceptions) { exp = ex; } }
if (exp != null || putNullWhenNoExceptionIsThrown) { exceptions.Add(exp); }
}
return exceptions?.ToArray();
}
例、代わりに:
var a = 19;
var b = 0;
var d = 0;
try { a = a / b; } catch { }
try { d = a + 5 / b; } catch { }
try { d = (a + 5) / (b + 1); } catch { }
あなたはできる:
var a = 19;
var b = 0;
var d = 0;
OnErrorResumeNext(
() =>{a = a / b;},
() =>{d = a + 5 / b;},
() =>{d = (a + 5) / (b + 1);}
);
私はVB6の古い帽子です。最初の短いレッスン...
次にエラー履歴書で使用する理由があります。主に読みやすさのためです。 VB6では、エラートラップを実装する2つの方法があります。このように、次にエラー履歴書で「インライン」を使用できます。
On Error Resume Next
<something that may throw an error>
If Err.Number <> 0 Then
<do something about this specific line of code>
Err.Clear()
End If
または、これを見るかもしれません:
Sub DoSomething
On Error Goto Handler1
<do something that causes an error>
On Error Goto Handler2
<do something that may cause an error>
Exit Sub
Handler1:
<log error or something>
Resume Next
Handler2:
<log error or something>
Resume Next
End Sub
しかし、古いVB6コードでは、おそらくこれも見るでしょう...
Sub PerformThis
On Error Resume Next
End Sub
いずれにせよ、これらのケースをキャッチを試してみるのは非常に簡単です...エラーを沈める必要がある場合は、エラーの履歴書を見るとクイック「インライン」を使用してください次にこれを行うだけです。
try { _objectinfo.Add(_object.attribute1); } catch (Exception _e) { }
コードをサブルーチンにカプセル化することにより、トライキャッチを呼び出しルーチンに上げることもできます...したがって、サブルーチン全体を沈める必要がある場合は...
try { PerformAction(); } catch (Exception _e) { }
これを実行して、パフォーマンス()サブルーチンにコードの上部に次にエラー履歴書が含まれている場合、呼び出しのサブルーチンでトライキャッチを使用します
幸運を...