vb.netでは、おそらく他の.net言語では、ジェネリッククラスのパラメータを取る例外クラスを定義してスローすることができます。たとえば、SomeThingBadHappenedException(Of T)を合法的に定義し、SomethingBadHappened(Of SomeType)をスローしてキャッチすることができます。これは、それぞれのコンストラクタを手動で定義することなく、例外ファミリーを作成する便利な方法を提供するようです。洗練された例外タイプは、コールスタックのさらに下にスローされる例外ではなく、実際に例外が予期している例外であることを保証するのに役立ちます。マイクロソフトでは、厳密に詳細なカスタム例外を使用する考え方は特に気にしないかもしれませんが、多くの既存の例外は予期せぬ場所から発生する可能性があります(たとえば、DLLからロードされるはずの関数を初めて呼び出すときに "FileNotFoundException" )カスタム例外をスローしてキャッチすることは、既存のものを使用することよりも安全だと思われます。ジェネリック型パラメータで例外を使用するのは良いか悪いですか
ジェネリッククラスの型パラメータが共変でも反逆(*)でもないため、SomethingBadHappened(Of SomeBaseType)としてのCatch ExceptionはSomethingBadHappened(OfDecandDerivedType)をキャッチしません。 。 SomethingBadHappened(Of U)から派生し、 "SomethingBadHappened(Of SomeDerivedType、SomeBaseType)"をスローするように "Catch Ex As SomethingBadHappened(Of T、U)"を定義することができますが、それはちょっとしたものです。 clunkyフォームまたは基本型を省略した形式(基本型の例外として捕らえられない)。
Generic型の例外を使用する考え方は何ですか? ?
(*)例外の派生型ではなくIException(Of Out T As Exception)の派生を捕捉できれば、共変の汎用例外タイプを定義することができます。もしIException(Of T)に "Self" propeが含まれていれば.netへT型のrty、Exceptionの派生Uをキャッチしようとすると、IException(Of U)もキャッチされますが、それは価値があるにはあまりに複雑すぎるでしょう。既存の例外階層で
補遺
、Fooクラスは、例えば、スローInvalidOperationExceptionは発生してはならないが、呼び出し元が処理しなければならないかもしれないが、予期せぬ状況に起因する多くの例外をキャッチせずに例外をキャッチする良い方法はありません。それはしないでください。クラスFooが独自の例外を定義することでその危険を避けることができますが、すべての "実際の"クラスでも1つのカスタム例外クラスが定義されていれば、カスタム例外クラスはすぐに圧倒される可能性があります。 CleanFailureException(Of Foo)のように何らかの理由で要求された操作が行われなかったが状態が妨害されていないことを示す場合はCleanerFailureException(Of Foo、Foo.Causes.KeyDuplicated CleanFailureException(Of Foo)から継承し、より正確な失敗の理由を示します。
私は、一般的な例外を使用する手段を見つけ出すことはできませんでしたが、それは少し不器用に感じることはありませんが、他の誰もより良い方法を見つけることができないというわけではありません。派生した例外の型は、必要に応じて機能することに注意してください唯一の実際の煩さは、障害が投げられたり捕らえられたりするたびに、派生の連鎖のすべてを特定することです。一般的な例外を使用しての
' Define some interfaces which are used to indicate which faults derive from others Interface IFault(Of T) End Interface Interface IFault(Of T, U As IFault(Of T)) End Interface Interface IFault(Of T, U As IFault(Of T), V As IFault(Of T, U)) End Interface ' Derive the exceptions themselves. Real code should include all the constructors, of course. Class CleanFailureException Inherits Exception Sub New(ByVal Msg As String, ByVal innerException As Exception) MyBase.New(Msg, innerException) End Sub End Class Class CleanFailureException(Of T) Inherits CleanFailureException Sub New(ByVal Msg As String, ByVal innerException As Exception) MyBase.New(Msg, innerException) End Sub End Class Class CleanFailureException(Of T, FaultType As IFault(Of T)) Inherits CleanFailureException(Of T) Sub New(ByVal Msg As String, ByVal innerException As Exception) MyBase.New(Msg, innerException) End Sub End Class Class CleanFailureException(Of T, FaultType As IFault(Of T), FaultSubType As IFault(Of T, FaultType)) Inherits CleanFailureException(Of T, FaultType) Sub New(ByVal Msg As String, ByVal innerException As Exception) MyBase.New(Msg, innerException) End Sub End Class Class CleanFailureException(Of T, FaultType As IFault(Of T), FaultSubType As IFault(Of T, FaultType), FaultSubSubType As IFault(Of T, FaultType, FaultSubType)) Inherits CleanFailureException(Of T, FaultType, FaultSubType) Sub New(ByVal Msg As String, ByVal innerException As Exception) MyBase.New(Msg, innerException) End Sub End Class ' Now a sample class to use such exceptions Class FileLoader Class Faults ' Effectively used as a namespace within a class Class FileParsingError Implements IFault(Of FileLoader) End Class Class InvalidDigit Implements IFault(Of FileLoader, FileParsingError) End Class Class GotADollarSignWhenIWantedAZeroOrOne Implements IFault(Of FileLoader, FileParsingError, InvalidDigit) End Class Class GotAPercentSignWhenIWantedASix Implements IFault(Of FileLoader, FileParsingError, InvalidDigit) End Class Class InvalidSeparator Implements IFault(Of FileLoader, FileParsingError) End Class Class SomeOtherError Implements IFault(Of FileLoader) End Class End Class ' Now a test routine to throw the above exceptions Shared Sub TestThrow(ByVal WhichOne As Integer) Select Case WhichOne Case 0 Throw New CleanFailureException(Of FileLoader, Faults.FileParsingError, Faults.InvalidDigit, Faults.GotADollarSignWhenIWantedAZeroOrOne) _ ("Oops", Nothing) Case 1 Throw New CleanFailureException(Of FileLoader, Faults.FileParsingError, Faults.InvalidDigit, Faults.GotAPercentSignWhenIWantedASix) _ ("Oops", Nothing) Case 2 Throw New CleanFailureException(Of FileLoader, Faults.FileParsingError, Faults.InvalidDigit) _ ("Oops", Nothing) Case 2 Throw New CleanFailureException(Of FileLoader, Faults.FileParsingError, Faults.InvalidSeparator) _ ("Oops", Nothing) Case 4 Throw New CleanFailureException(Of FileLoader, Faults.FileParsingError) _ ("Oops", Nothing) Case 5 Throw New CleanFailureException(Of FileLoader, Faults.SomeOtherError) _ ("Oops", Nothing) Case 6 Throw New CleanFailureException(Of FileLoader) _ ("Oops", Nothing) Case 7 Throw New CleanFailureException(Of Integer) _ ("Oops", Nothing) End Select End Sub ' A routine to see how each exception type gets caught Shared Sub TestFaults() For i As Integer = 0 To 7 Try TestThrow(i) Catch ex As CleanFailureException(Of FileLoader, Faults.FileParsingError, Faults.InvalidDigit, Faults.GotADollarSignWhenIWantedAZeroOrOne) Debug.Print("Caught {0} as GotADollarSignWhenIWantedAZeroOrOne", ex.GetType) Catch ex As CleanFailureException(Of FileLoader, Faults.FileParsingError, Faults.InvalidDigit) Debug.Print("Caught {0} as InvalidDigit", ex.GetType) Catch ex As CleanFailureException(Of FileLoader, Faults.FileParsingError) Debug.Print("Caught {0} as FileParsingError", ex.GetType) Catch ex As CleanFailureException(Of FileLoader) Debug.Print("Caught {0} as FileLoader", ex.GetType) Catch ex As CleanFailureException Debug.Print("Caught {0} as CleanFailureException", ex.GetType) End Try Next End Sub End Class
補遺2
少なくとも一つの利点は、1つがリフレクションを使用しない限り、作成する例外を定義するジェネリック型パラメータを持つ便利な例外の工場を持ってすることはできませんしながら、多少不快な方法ではありますが、ジェネリック型パラメータを含む例外クラスを作成することは可能です。誰かが興味を持っているなら、私はそれを含むコード例を更新することができます。
それ以外の場合、派生クラスごとに同じコンストラクターコードを繰り返さずにカスタム例外を定義するためのまともなコーディングパターンはありますか?私は本当にvb.netおよび/またはc#が単一のパラメータのないクラス固有のコンストラクタを指定し、各親のオーバーロードに対してパブリックコンストラクタを自動的に作成する構文を含むことを望みます。
さらにいくつかの検討に補遺3
は、それは本当に多くの場合、必要なものがスローされた例外がクラスに縛られていないことであるように思えるが、むしろ例外との間で定義された関係を持っていますオブジェクトインスタンス。残念ながら、catch SomeExceptionType(ThisParticularFoo)の概念を定義する明確な方法はありません。最善の策は、 "NoCorruptionOutisde"述部を持つカスタム基本例外クラスを定義し、 "Ex.NoCorruptionOutside(MyObjectInstance)"を指定したときにCorruptObjectExceptionをキャッチすることです。それはどうやって聞こえる?
この点は何ですか?コード例は、急いでそれをクリアするでしょう。 –
@Chris Shouts:編集例です。 – supercat