When catching a general exception, how can I deter

2019-04-09 18:43发布

问题:

When catching an exception in .NET, you can have as many type-specific exception blocks as needed. But I usually try to have at least one "general" exception catch block. But is there a way to get the type of the "real" exception thrown that is caught by the generic exception handler, perhaps using reflection?

For example, if I have

Catch ex As System.ServiceModel.FaultException(Of InvalidUser)
     ProcessModuleLoadException(Me, ex)
Catch ex As System.ServiceModel.FaultException(Of SQLExceptions)
     ProcessModuleLoadException(Me, ex)
Catch ex As System.ServiceModel.FaultException(Of DataNullReference)
     ProcessModuleLoadException(Me, ex)
Catch ex As System.ServiceModel.FaultException
     ProcessModuleLoadException(Me, ex)
Catch ex As Exception
     ProcessModuleLoadException(Me, ex)

(I have broken them out for debugging, even though I do the same thing with each exception).

In short, in "Catch ex As System.ServiceModel.FaultException" I want to examine "ex" and get the base "real" type of the exception, either as a type (mostly for debugging so I can add another catch block) or as a string (for logging).

But, inside the Catch block, "ex" has already been cast to it's parent class, so any original properties and information about the original exception seem to be lost.

Suggestions?

回答1:

Even though the Exception has been cast to its parent class, you can still call GetType to obtain its underlying concrete type (pardon my C#):

try {
    // Do stuff
}
catch(Exception ex) {
    Type exceptionType = ex.GetType();
}

If this is just for diagnostic purposes, you can log ex.ToString(), which includes the underlying type by default (in addition to the stack trace, etc.) like this:

System.ArgumentException: lastName
   at Tests.Program.Main(String[] args) in ...\Program.cs:line 22


回答2:

.GetType will still return its actual type.



回答3:

This only a slight modification from Jeff's answer:

I was looking for something like what Chris is describing, and specifically I wanted to handle the original exception after it had been thrown again by a few generic exceptions, and have only one handler that I could call for all entry points. And since re-throwing an exception will wrap it with its own exception type, we need to add loop to go through the inner exceptions, and check the first exception thrown.

So here's the code I ended up with:

Public Sub HandelException(myEx As Exception)
    Try
        Dim InnerEx As Exception = myEx
        Do Until InnerEx.InnerException Is Nothing
            InnerEx = InnerEx.InnerException
        Loop

        If InnerEx.GetType = GetType(Exception1) Then
            'Handle exception type 1
        ElseIf InnerEx.GetType = GetType(Exception2) Then
            'Handle exception type 2
        ElseIf InnerEx.GetType = GetType(Exception3) Then
            'Handle exception type 3
        ElseIf InnerEx.GetType = GetType(Exception4) Then
            'Handle exception type 4
        ElseIf InnerEx.GetType = GetType(Exception) Then
            'Handle generic system exception
        End If
    Catch ex As Exception
        'Handel unlikely exception in exception handler LOL.
    End Try
End Sub

The advantage of this is that you could have an extensive range of exception types you handle throughout the program, with lots of handling code, but you could handle them all in one place.

I know this reply is a little late for this question, but I thought I would share, if perhaps to help anyone looking for the same thing I was looking for.



回答4:

What about catching it as a generic system exception then using the "is" lingo to test the actual type?

try
{
    // Something
}
catch(Exception ex)
{
    // Single catch block - catches as generic system exception
    if(ex is FaultException) {
        //Process as FaultEx
    }
    if(ex is ArithmeticException) {
        //Process as ArithEx
    }
    if(ex is ArgumentException) {
        //Process as ArgEx
    }
}
finally
{
    //Cleanup
}