アプリケーションが予期しないすべての条件に対して作成された例外があります。 UserNameNotValidException
、PasswordNotCorrectException
など。
しかし、私はそれらの条件の例外を作成するべきではないと言われました。私のUMLでは、これらはメインフローの例外ですが、なぜ例外ではないのですか?
例外を作成するためのガイダンスまたはベストプラクティスはありますか?
アプリケーションが予期しないすべての条件に対して作成された例外があります。 UserNameNotValidException
、PasswordNotCorrectException
など。
しかし、私はそれらの条件の例外を作成するべきではないと言われました。私のUMLでは、これらはメインフローの例外ですが、なぜ例外ではないのですか?
例外を作成するためのガイダンスまたはベストプラクティスはありますか?
私の個人的なガイドラインは次のとおりです。現在のコード ブロックの基本的な仮定が偽であることが判明した場合、例外がスローされます。
例 1: 任意のクラスを検査し、そのクラスが List<> から継承されている場合に true を返す関数があるとします。この関数は、「このオブジェクトは List の子孫ですか?」という質問をします。この関数の操作には灰色の領域がないため、この関数は決して例外をスローするべきではありません。すべてのクラスが List<> から継承するかしないかのどちらかであるため、答えは常に「はい」または「いいえ」です。
例 2: List<> を調べ、その長さが 50 を超える場合は true を返し、長さがそれ未満の場合は false を返す別の関数があるとします。この関数は、「このリストには 50 を超える項目がありますか?」という質問をします。しかし、この質問は、与えられたオブジェクトがリストであると仮定しています。NULL を渡した場合、その仮定は誤りです。その場合、関数がtrueまたはfalse を返す場合、それは独自の規則に違反しています。関数は何も返すことができず、質問に正しく答えたと主張できません。したがって、返されません-例外がスローされます。
これは、 「ロードされた質問」の論理的誤謬に匹敵します。すべての関数は質問をします。与えられた入力がその質問を誤謬にする場合は、例外をスローします。この線は void を返す関数で描くのが難しくなりますが、最終的には、入力に関する関数の仮定に違反した場合、正常に戻る代わりに例外をスローする必要があります。
この方程式の反対側は、関数が頻繁に例外をスローしていることがわかった場合は、おそらくそれらの仮定を改善する必要があるということです。
彼らは普通に起こることだからです。例外は制御フローメカニズムではありません。ユーザーはパスワードを間違えることがよくありますが、これは例外的なケースではありません。UserHasDiedAtKeyboard
例外は本当にまれなこと、タイプの状況であるべきです。
私の小さなガイドラインは、偉大な本「Code complete」の影響を大きく受けています。
ユーザー名が有効でない場合やパスワードが正しくない場合も例外ではありません。これらは、通常の操作の流れで期待すべきことです。例外は、通常のプログラム操作の一部ではなく、かなりまれなものです。
編集:呼び出しを見ただけではメソッドが例外をスローするかどうかわからないため、例外を使用するのは好きではありません。そのため、例外は、状況を適切に処理できない場合にのみ使用する必要があります(「メモリ不足」または「コンピュータが起動している」と考えてください)。
経験則の1つは、通常は予測できない何かの場合に例外を使用することです。例としては、データベース接続、ディスク上のファイルの欠落などがあります。予測可能なシナリオ、つまりユーザーが不正なパスワードでログインしようとしている場合は、ブール値を返し、状況を適切に処理する方法を知っている関数を使用する必要があります。誰かがパスワードを間違って入力したという理由だけで例外をスローして、実行を突然終了したくない場合。
他の人は、ユーザーがタイプミスした場合、通常のフローでは不正なログインが予想されるため、例外を使用すべきではないと提案しています。私は同意せず、理由がわかりません。ファイルを開くことと比較してください。ファイルが存在しないか、何らかの理由で利用できない場合、フレームワークによって例外がスローされます。上記のロジックを使用することは、Microsoftによる間違いでした。彼らはエラーコードを返したはずです。解析、Webリクエストなどについても同じです。
私は通常のフローの悪いログイン部分を考慮していません、それは例外的です。通常、ユーザーは正しいパスワードを入力しますが、ファイルは存在します。例外的なケースは例外的であり、それらに例外を使用することはまったく問題ありません。戻り値をスタックのnレベルまで伝播することによってコードを複雑にすることは、エネルギーの浪費であり、コードが乱雑になる結果になります。おそらく機能する可能性のある最も単純なことを行います。エラーコードを使用して時期尚早に最適化しないでください。定義上、例外的なものが発生することはめったにありません。例外をスローしない限り、例外は発生しません。
現在の状態から抜け出すためにできることがない場合にのみ、例外をスローする必要があると思います。たとえば、メモリを割り当てていて、割り当てるものがない場合です。あなたが言及した場合、あなたはそれらの状態から明らかに回復することができ、それに応じてあなたの発信者にエラーコードを返すことができます。
この質問への回答を含め、「例外的な」状況でのみ例外をスローする必要があるというアドバイスがたくさん表示されます。これは一見合理的なように見えますが、1つの質問(「いつ例外をスローする必要があるか」)を別の主観的な質問(「何が例外的か」)に置き換えるため、欠陥のあるアドバイスです。代わりに、ハーブサッターのアドバイスに従ってください(C ++の場合、 DrDobbsの記事「例外の使用時期と方法」およびAndreiAlexandrescuの著書「C++コーディング標準」で入手できます):例外をスローするのは、
なぜこれが良いのですか?質問を、前提条件、事後条件、および不変条件に関するいくつかの質問に置き換えませんか?これは、いくつかの関連する理由から優れています。
throw
特性ですが、決定は実装の詳細です。設計とその実装を別々に検討する必要があることを念頭に置いておく必要があります。メソッドを実装する際の私たちの仕事は、設計の制約を満たすものを作成することです。catch
句に移動されます。例外はややコストのかかる影響です。たとえば、無効なパスワードを提供するユーザーがいる場合は、通常、失敗フラグまたはそれが無効であることを示すその他のインジケーターを返すことをお勧めします。
これは、例外の処理方法、真の不正な入力、および一意の重大な停止項目は例外である必要がありますが、失敗したログイン情報によるものではありません。
いつ例外を使用するかについて、厳格なルールはありません。ただし、それらを使用するか使用しないかには、正当な理由があります。
例外を使用する理由:
例外を使用しない理由:
一般に、C++ や C# よりも Java で例外を使用する傾向があります。これは、宣言されているかどうかに関係なく、例外は基本的に関数の正式なインターフェイスの一部であると私は考えているためです。呼び出しコードを中断します。Java IMO でそれらを使用する最大の利点は、呼び出し元が例外を処理する必要があることを知っていることです。これにより、正しい動作の可能性が向上します。
このため、どの言語でも、コードのレイヤーまたは API のすべての例外を共通のクラスから常に派生させ、呼び出し元のコードが常にすべての例外をキャッチすることを保証できるようにします。また、API やライブラリを作成するときに、実装固有の例外クラスをスローするのは良くないと考えます (つまり、呼び出し元が受け取る例外がインターフェイスのコンテキストで理解できるように、下位層から例外をラップします)。
Java では、一般例外とランタイム例外を区別しており、後者は宣言する必要がないことに注意してください。エラーがプログラムのバグの結果であることがわかっている場合にのみ、ランタイム例外クラスを使用します。
何度も何度も例外を引き起こす可能性があるループ内で実行されているコードである場合、例外をスローすることは良いことではありません。大きな N ではかなり遅いからです。問題。BaseException などと呼ばれる、すべてが継承する基本例外があることを確認してください。BaseException は System.Exception を継承しますが、例外はすべて BaseException を継承します。同様のタイプをグループ化する例外タイプのツリーを作成することもできますが、これはやり過ぎかもしれませんし、そうでないかもしれません。
したがって、簡単な答えは、重大なパフォーマンスの低下を引き起こさない場合 (多くの例外をスローしない限り、そうすべきではありません)、先に進むということです。
例外クラスは「通常の」クラスに似ています。異なるフィールドと異なる操作を持つ異なるタイプのオブジェクトである場合は、新しいクラスを作成します。
経験則として、例外の数と例外の粒度のバランスを取る必要があります。メソッドが 4 ~ 5 個以上の異なる例外をスローする場合、おそらくそれらのいくつかをより「一般的な」例外 (たとえば、「AuthenticationFailedException」の場合) にマージし、例外メッセージを使用して何が問題なのかを詳しく説明できます。コードでそれぞれを異なる方法で処理しない限り、多くの例外クラスを作成する必要はありません。その場合は、発生したエラーを含む列挙型を返す必要があります。これでだいぶスッキリ。
例外をスローするための経験則は非常に単純です。これは、コードが UNRECOVERABLE INVALID 状態になったときに行います。データが侵害された場合、またはその時点までに発生した処理を巻き戻すことができない場合は、それを終了する必要があります。他に何ができますか?処理ロジックは最終的に他の場所で失敗します。何らかの形で回復できる場合は、それを行い、例外をスローしないでください。
特定のケースで、お金の引き出しを受け入れるなどのばかげたことをすることを余儀なくされた場合にのみ、ユーザー/パスワードを確認して、何か悪いことが起こったことを通知し、さらなる損害を防ぐために例外をスローしてプロセスを終了する必要があります.
私はそこまでジャポロックに同意します-手術の結果について不確かな場合は、受け入れを投げてください. API の呼び出し、ファイルシステムへのアクセス、データベース呼び出しなど。プログラミング言語の「境界」を越えて移動するときはいつでも。
追加したいのですが、お気軽に標準例外をスローしてください。「別の」こと (無視、電子メール、ログ、Twitter のクジラの写真を表示するなど) を行う場合を除き、カスタム例外を気にしないでください。
一般に、アプリケーションで発生する可能性のある「例外的な」ものに対して例外をスローする必要があります
あなたの例では、これらの例外は両方とも、パスワード/ユーザー名の検証を介してそれらを呼び出しているように見えます。その場合、誰かがユーザー名/パスワードを間違って入力することは本当に例外的ではないと主張することができます.
これらは UML のメイン フローの「例外」ですが、処理の「分岐」にすぎません。
passwd ファイルまたはデータベースにアクセスしようとしてアクセスできなかった場合、それは例外的なケースであり、例外をスローする必要があります。
まず、API のユーザーが特定のきめ細かい障害に関心がない場合、特定の例外を設けても意味がありません。
ユーザーにとって何が役立つかを知ることはしばしば不可能であるため、より良いアプローチは、特定の例外を用意することですが、それらが共通のクラス (たとえば、std::exception または C++ でのその派生) から継承されるようにすることです。これにより、クライアントは、選択した場合は特定の例外をキャッチでき、気にしない場合はより一般的な例外をキャッチできます。
簡単な答えは、操作が不可能な場合 (アプリケーションまたはビジネス ロジックに違反するため) です。メソッドが呼び出され、そのメソッドが実行するように記述されていることを実行できない場合は、例外をスローします。良い例は、指定されたパラメーターを使用してインスタンスを作成できない場合、コンストラクターは常に ArgumentExceptions をスローすることです。もう 1 つの例は InvalidOperationException です。これは、別のメンバーまたはクラスのメンバーの状態が原因で操作を実行できない場合にスローされます。
あなたの場合、Login(username, password) のようなメソッドが呼び出された場合、ユーザー名が有効でない場合、パスワードが正しくない場合は UserNameNotValidException または PasswordNotCorrectException をスローするのが正しいです。ユーザーは指定されたパラメータを使用してログインできない (つまり、認証に違反するため不可能である) ため、例外をスローします。私はあなたの2つの例外がArgumentExceptionから継承するかもしれませんが。
そうは言っても、ログインの失敗が非常に一般的であるために例外をスローしたくない場合は、代わりに、さまざまな失敗を表す型を返すメソッドを作成するという 1 つの戦略があります。次に例を示します。
{ // class
...
public LoginResult Login(string user, string password)
{
if (IsInvalidUser(user))
{
return new UserInvalidLoginResult(user);
}
else if (IsInvalidPassword(user, password))
{
return new PasswordInvalidLoginResult(user, password);
}
else
{
return new SuccessfulLoginResult();
}
}
...
}
public abstract class LoginResult
{
public readonly string Message;
protected LoginResult(string message)
{
this.Message = message;
}
}
public class SuccessfulLoginResult : LoginResult
{
public SucccessfulLogin(string user)
: base(string.Format("Login for user '{0}' was successful.", user))
{ }
}
public class UserInvalidLoginResult : LoginResult
{
public UserInvalidLoginResult(string user)
: base(string.Format("The username '{0}' is invalid.", user))
{ }
}
public class PasswordInvalidLoginResult : LoginResult
{
public PasswordInvalidLoginResult(string password, string user)
: base(string.Format("The password '{0}' for username '{0}' is invalid.", password, user))
{ }
}
ほとんどの開発者は、例外をスローすることによってオーバーヘッドが発生するため、例外を避けるように教えられています。リソースを意識するのは素晴らしいことですが、通常、アプリケーションの設計を犠牲にすることはありません。それがおそらく、2 つの例外をスローしないように言われた理由です。例外を使用するかどうかは、通常、例外が発生する頻度に要約されます。それがかなり一般的であるか、またはかなり期待できる結果である場合、これはほとんどの開発者が例外を回避し、代わりに別のメソッドを作成して失敗を示す場合です。これは、リソースの消費が想定されるためです。
Try() パターンを使用して、説明したようなシナリオで例外の使用を回避する例を次に示します。
public class ValidatedLogin
{
public readonly string User;
public readonly string Password;
public ValidatedLogin(string user, string password)
{
if (IsInvalidUser(user))
{
throw new UserInvalidException(user);
}
else if (IsInvalidPassword(user, password))
{
throw new PasswordInvalidException(password);
}
this.User = user;
this.Password = password;
}
public static bool TryCreate(string user, string password, out ValidatedLogin validatedLogin)
{
if (IsInvalidUser(user) ||
IsInvalidPassword(user, password))
{
return false;
}
validatedLogin = new ValidatedLogin(user, password);
return true;
}
}
私にとっては、必要な技術ルールまたはビジネス ルールが失敗した場合に例外をスローする必要があります。たとえば、車のエンティティが 4 つのタイヤの配列に関連付けられている場合 ... 1 つ以上のタイヤが null の場合 ... 例外が発生する必要があります "NotEnoughTiresException" 、システムのさまざまなレベルでキャッチされ、重要なロギングによる意味。さらに、null をフロー制御して car のインスタンス化を防止しようとすると、. そもそもタイヤがヌルであってはならないので、問題の原因を決して見つけられないかもしれません。
一般的に、すべての原理主義は地獄につながると思います。
例外駆動型のフローで終わることは確かに望ましくありませんが、例外を完全に回避することも悪い考えです。両方のアプローチのバランスを見つける必要があります。私がやりたくないことは、例外的な状況ごとに例外タイプを作成することです。それは生産的ではありません。
私が一般的に好むのは、システム全体で使用される 2 つの基本的な例外タイプ、LogicalExceptionとTechnicalExceptionを作成することです。これらは、必要に応じてサブタイプによってさらに区別できますが、通常は必要ありません。
技術的な例外は、データベース サーバーがダウンしている、Web サービスへの接続が IOException をスローしたなど、本当に予期しない例外を示します。
一方、論理例外は、それほど深刻ではないエラー状況を上位層に伝播するために使用されます (通常は、何らかの検証結果)。
論理例外でさえ、プログラム フローを制御するために定期的に使用することを意図したものではなく、フローが実際に終了する必要がある状況を強調することを意図していることに注意してください。Java で使用する場合、どちらの例外タイプもRuntimeExceptionサブクラスであり、エラー処理は高度にアスペクト指向です。
したがって、ログインの例では、 AuthenticationException のようなものを作成し、 UsernameNotExisting、PasswordMismatchなどの列挙値によって具体的な状況を区別するのが賢明かもしれません。そうすれば、巨大な例外階層を持つことにはならず、catch ブロックを保守可能なレベルに保つことができます。 . 例外を分類し、何をどのようにユーザーに伝達するかをよく知っているため、一般的な例外処理メカニズムを簡単に採用することもできます。
一般的な使用方法は、ユーザーの入力が無効な場合に、Web サービスの呼び出し中に LogicalException をスローすることです。例外は SOAPFault 詳細にマーシャリングされ、クライアント上で再び例外にマーシャリング解除されます。その結果、例外がそのフィールドに適切にマッピングされているため、特定の Web ページ入力フィールドに検証エラーが表示されます。
これは確かに唯一の状況ではありません。例外をスローするために Web サービスをヒットする必要はありません。例外的な状況 (フェイルファストが必要な場合など) では自由に行うことができます。すべてはあなたの裁量に任されています。
例外は、異常な動作、エラー、障害などのイベントを対象としています。機能的な動作、ユーザー エラーなどは、代わりにプログラム ロジックで処理する必要があります。不適切なアカウントまたはパスワードは、ログイン ルーチンのロジック フローの予期される部分であるため、例外なくこれらの状況を処理できる必要があります。
私の考えでは、基本的な問題は、条件が発生した場合に呼び出し元が通常のプログラムフローを継続したいと思うかどうかということです。わからない場合は、doSomethingメソッドとtrySomethingメソッドを別々に使用してください。前者はエラーを返し、後者はエラーを返しません。または、失敗した場合に例外をスローするかどうかを示すパラメーターを受け入れるルーチンを用意します。リモートシステムにコマンドを送信し、応答を報告するクラスについて考えてみます。特定のコマンド(再起動など)により、リモートシステムは応答を送信しますが、一定時間応答しなくなります。したがって、「ping」コマンドを送信して、リモートシステムが応答しない場合に例外をスローすることなく、妥当な時間内に応答するかどうかを確認できると便利です。t(呼び出し元は、最初の数回の「ping」試行が失敗することをおそらく期待しますが、最終的には機能します)。一方、次のような一連のコマンドがある場合:
exchange_command( "open tempfile"); exchange_command( "一時ファイルデータを書き込む{何でも}"); exchange_command( "一時ファイルデータを書き込む{何でも}"); exchange_command( "一時ファイルデータを書き込む{何でも}"); exchange_command( "一時ファイルデータを書き込む{何でも}"); exchange_command( "tempfileを閉じる"); exchange_command( "tempfileをrealfileにコピー");
シーケンス全体を中止するには、操作が失敗した場合があります。各操作をチェックして成功したことを確認することもできますが、コマンドが失敗した場合は、exchange_command()ルーチンで例外をスローする方が便利です。
実際、上記のシナリオでは、いくつかの障害処理モードを選択するパラメーターがあると便利な場合があります。例外をスローしない、通信エラーのみの例外をスローする、またはコマンドが「成功」を返さない場合は例外をスローする「表示。
例外をスローすると、スタックが巻き戻され、パフォーマンスに影響を与えます (認められているように、最新のマネージド環境ではそれが改善されています)。ネストされた状況で繰り返し例外をスローしてキャッチすることは、悪い考えです。
おそらくそれよりも重要なのは、例外は例外的な条件のためのものです。コードの可読性が損なわれるため、通常の制御フローには使用しないでください。
「PasswordNotCorrectException」は、例外を使用する良い例ではありません。ユーザーがパスワードを間違えることは予想されるため、私見では例外ではありません。おそらくそれから回復して、素敵なエラーメッセージを表示することさえあるので、これは単なる有効性チェックです。
未処理の例外は最終的に実行を停止します - これは良いことです。false、null、またはエラー コードを返す場合は、プログラムの状態をすべて自分で処理する必要があります。どこかで条件をチェックするのを忘れると、プログラムが間違ったデータで実行され続け、何がどこで起こったのかを理解するのに苦労する可能性があります。
もちろん、空の catch ステートメントでも同じ問題が発生する可能性がありますが、少なくともそれらを見つける方が簡単で、ロジックを理解する必要はありません。
経験則として:
必要のない場所や、単にエラーから回復できない場所で使用してください。
例外のスローを回避する主な理由は、例外のスローに伴う多くのオーバーヘッドがあるためです。
以下の記事で述べられていることの 1 つは、例外は例外的な条件とエラーに対するものであるということです。
間違ったユーザー名は、必ずしもプログラム エラーではなく、ユーザー エラーです...
.NET 内の例外の適切な出発点は次のとおりです: http://msdn.microsoft.com/en-us/library/ms229030(VS.80).aspx
私がキャッチする条件は 3 種類あります。
入力の誤りや欠落も例外ではありません。クライアント側の js とサーバー側の正規表現の両方を使用して、属性を検出、設定し、メッセージを含む同じページに転送します。
AppException. これは通常、コードで検出してスローする例外です。言い換えれば、これらはあなたが期待するものです (ファイルは存在しません)。ログに記録し、メッセージを設定して、一般的なエラー ページに戻ります。このページには通常、何が起こったのかについての情報が少しあります。
予期しない例外。これらはあなたが知らないものです。詳細をログに記録し、一般的なエラー ページに転送します。
お役に立てれば
セキュリティはあなたの例と混同されています:ユーザー名が存在することを攻撃者に伝えるべきではありませんが、パスワードは間違っています。これは、共有する必要のない余分な情報です。「ユーザー名またはパスワードが正しくありません」と言ってください。
例外の使用には哲学的な問題があります。基本的に、特定のシナリオが発生することを期待していますが、それを明示的に処理するのではなく、問題を「別の場所」で処理するようにプッシュしています。そして、その「他の場所」がどこにあるのかは、誰でも推測できます。
その条件には、少し一般的な例外を使用できます。たとえば、ArgumentException は、メソッドのパラメーターに問題が発生した場合に使用することを意図しています (ArgumentNullException を除く)。通常、LessThanZeroException、NotPrimeNumberException などの例外は必要ありません。メソッドのユーザーについて考えてみてください。彼女が具体的に処理したい条件の数は、メソッドがスローする必要がある例外の種類の数と同じです。このようにして、どの程度詳細な例外が発生するかを判断できます。
ところで、ライブラリのユーザーが例外を回避できるように、常に何らかの方法を提供するようにしてください。TryParse は良い例です。int.Parse を使用して例外をキャッチする必要がないように存在します。あなたの場合、ユーザー名が有効かどうか、またはパスワードが正しいかどうかを確認する方法をいくつか提供して、ユーザー (またはあなた) が多くの例外処理を行う必要がないようにすることができます。これにより、コードが読みやすくなり、パフォーマンスが向上することが期待されます。
最終的には、例外処理を使用してこのようなアプリケーション レベルのエラーに対処する方が役立つか、またはステータス コードを返すような独自のホームロール メカニズムを介して対処する方が役立つかどうかが決定されます。どちらが優れているかという厳格なルールはないと思いますが、次のように考えます。
例外が適切かどうかを判断する際に考慮すべきいくつかの有用な事柄:
例外候補が発生した後に実行するコードのレベル、つまり、コール スタックの何層をアンワインドする必要があるか。通常、例外は、発生した場所のできるだけ近くで処理する必要があります。ユーザー名/パスワードの検証では、通常、例外を発生させるのではなく、同じコード ブロックでエラーを処理します。したがって、例外はおそらく適切ではありません。(OTOH、ログイン試行が 3 回失敗した後、制御フローが別の場所に移動する可能性があり、ここでは例外が適切である可能性があります。)
このイベントは、エラー ログに表示したいものですか? すべての例外がエラー ログに書き込まれるわけではありませんが、エラー ログのこのエントリが役立つかどうかを尋ねると便利です。
例外には、主に次の 2 つのクラスがあります。
1) システム例外 (データベース接続が失われたなど) または 2) ユーザー例外。(例: ユーザー入力の検証、「パスワードが正しくありません」)
独自のユーザー例外クラスを作成すると役立つことがわかりました。ユーザー エラーをスローしたい場合は、別の方法で処理する必要があります (つまり、ユーザーに表示されるリソース エラー)。メインのエラー ハンドラーで行う必要があるのは、オブジェクトの種類を確認することだけです。 :
If TypeName(ex) = "UserException" Then
Display(ex.message)
Else
DisplayError("An unexpected error has occured, contact your help desk")
LogError(ex)
End If
例外とエラーコード引数を返すことは、哲学ではなくフロー制御に関するものでなければなりません (エラーがどのように「例外的」であるか):
void f1() throws ExceptionType1, ExceptionType2 {}
void catchFunction() {
try{
while(someCondition){
try{
f1();
}catch(ExceptionType2 e2){
//do something, don't break the loop
}
}
}catch(ExceptionType1 e1){
//break the loop, do something else
}
}
ここに私の提案があります:
このような例外を処理するには、より多くの時間とメモリがかかるため、例外をスローするのが常に良い方法だとは思いません。
私の考えでは、何かが「親切で丁寧な」方法で処理できる場合 (これは、「if を使用してそのようなエラーを予測できる場合」などを意味します)、「例外」の使用を避けるべきですが、フラグを返すだけです。 "false" のように、詳細な理由を伝える外側のパラメーター値を使用します。
例として、次のようなクラスを作成できます。
public class ValueReturnWithInfo<T>
{
public T Value{get;private set;}
public string errorMsg{get;private set;}
public ValueReturnWithInfo(T value,string errmsg)
{
Value = value;
errMsg = errmsg;
}
}
エラーの代わりに、そのような「複数の値が返される」クラスを使用できます。これは、例外の問題を処理するためのより適切で丁寧な方法のようです。
ただし、一部のエラーを「if」で簡単に記述できない場合 (これはプログラミングの経験に依存します)、(FileIO 例外など)、例外をスローする必要があることに注意してください。