简体   繁体   中英

Trying to catch a FormatException error fails. Only Exception can catch it?

I have a method that accepts random data at runtime (it could be string , int , etc.) and then it tries adding this data to a list of a random type (eg List<byte> , List<int> , etc.).

Due to the unpredictable nature of this, I have added 2 error handling routines. One to catch a FormatException error and do some specific actions to fix the data. And secondly, I've also added a general catch-all for Exception so if another error I'm not expecting is thrown, I can display the details and exit the application gracefully.

The weird issue I'm having (or at least it seems weird to me), is that whenever a FormatException error is thrown, my Catch (FormatException ex) does nothing and instead the error is being caught by Catch (Exception ex) . So rather than being able to handle the error properly, the application exits instead.

To help isolate this, I've created a small example C# WinForms program that replicates the issue.

Here's the main form code:

private void button1_Click(object sender, EventArgs e)
{
    // This works normally        
    ErrorClass.TestCatchFormatException<string, string>("abc", "def");

    // This also works normally        
    ErrorClass.TestCatchFormatException<int, int>("123", "456");

    // This should raise a FormatException error but only Exception catches it???
    ErrorClass.TestCatchFormatException<int, string>("abc", "456"); 
}

And here's the code for my 2 classes:

public class DataClass<T, U>
{
    public T Data1 { get; set; }
    public U Data2 { get; set; }
}

public static class ErrorClass
{
    public static void TestCatchFormatException<T, U>(dynamic inputString, dynamic inputString2)
        where T : IComparable<T>
        where U : IComparable<U>
    {
        try
        {
            List<DataClass<T, U>> theList = new List<DataClass<T, U>>();
            TypeConverter converter1 = TypeDescriptor.GetConverter(typeof(T));
            TypeConverter converter2 = TypeDescriptor.GetConverter(typeof(U));

            theList.Add(new DataClass<T, U>
            {
                Data1 = converter1.ConvertFrom(inputString.ToString()),
                Data2 = converter2.ConvertFrom(inputString2.ToString())
            });

            MessageBox.Show(
                "Data1 Value is: " + theList[0].Data1.ToString() + "\n"
                + "Data1 Type is: " + theList[0].Data1.GetType().ToString() + "\n"
                + "Data2 Value is: " + theList[0].Data2.ToString() + "\n"
                + "Data2 Type is: " + theList[0].Data2.GetType().ToString());
        }

        catch (FormatException ex)
        {
            // Catches nothing for some reason               
            MessageBox.Show("Caught FormatException\n\n" + ex.Message + "\n\n" + ex.InnerException);
        }

        catch (Exception ex)
        {
            // This catches the error but InnerException says the error is of type FormatException.  
            // Yet FormatException doesn't catch it???
            MessageBox.Show("Caught Exception\n\n" + ex.Message + "\n\n" + ex.InnerException);
        }
    }
}

Even weirder is that when I look at the InnerException the catch-all Exception generates, it says this:

System.FormatException: Input string was not in a correct format.

So it is detecting it as a FormatException error. Yet for some reason, catching FormatException does nothing and only Exception can catch it.

Does anyone know what I'm doing wrong here?

Your FormatException is being wrapped in some other Exception type. That's why the .InnerException property has a FormatException . Try calling .GetType on the exception you are getting to see the wrapping type, and catch that instead.

BaseNumberConverter.ConvertFrom() internally calls a helper function to throw an exception:

public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) {
     ...
        catch (Exception e) {
            throw FromStringError(text, e);
        }
    }
    return base.ConvertFrom(context, culture, value);
}

The implementation of FromStringError is:

internal virtual Exception FromStringError(string failedText, Exception innerException) {
        return new Exception(SR.GetString(SR.ConvertInvalidPrimitive, failedText, TargetType.Name), innerException);
}

So it throws an Exception that wraps the actual FormatException and adds some additional information (namely the value it's trying to convert and the type it's trying to convert to). Why it doesn't throw another FormatException I don't know.

Prior to C# 6 there was no way to create a catch that would catch based on the InnerException . You'd have to catch Exception and inspect the InnerException type to handle it differently.

With C# 6 you can use an exception filter:

catch (Exception ex) when (ex.InnerExcpetion is FormatException)
{
    // Catches nothing for some reason               
    MessageBox.Show("Caught FormatException\n\n" + ex.Message + "\n\n" + ex.InnerException);
}

catch (Exception ex)
{
    // This catches the error but InnerException says the error is of type FormatException.  
    // Yet FormatException doesn't catch it???
    MessageBox.Show("Caught Exception\n\n" + ex.Message + "\n\n" + ex.InnerException);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM