13

I have code that attempts a type conversion. If it fails, I want to try something else, and if that also fails, then rethrow the original exception attempted by the first conversion. The problem is that the only way I know of to rethrow is to have 'throw;' sitting at the end of the catch block. What happens when I only want the rethrow to happen from within another catch block?

try 
{
    valueFromData = Convert.ChangeType(valueFromData, pi.PropertyType);
} 
catch(InvalidCastException e)
{
    Debug.WriteLine(String.Concat("Info - Direct conversion failed. Attempting to convert using String as an intermidiate type."));
    try { valueFromData = Convert.ChangeType(valueFromData.ToString(), pi.PropertyType); }
    catch { throw e; }
}

As you can see above, I have to use 'throw e;', which resets the call stack.

Only workaround I've though of so far is (imo) gross:

bool handled = true;
... 
catch { handled = false; }
if( !handled ) throw;
Community
  • 1
  • 1
Alain
  • 26,663
  • 20
  • 114
  • 184
  • 1
    Is this something you would be able to do with TryParse? – Adam Wenger Oct 25 '11 at 14:06
  • 1
    out of interest what are you doing? Throwing exceptions are really expensive. You would be better off trying to use tryPase for the likely types first. – Ross Dargan Oct 25 '11 at 14:06
  • The property types are only known at runtime (property info), so TryParse (a function only possessed by some types), can't be called. If you're curious, the purpose of the above code is to allow large objects to be constructed by locating their own properties in a DataRow. – Alain Oct 25 '11 at 14:12
  • Set up a related question for the whole conversion thing here: http://stackoverflow.com/questions/7891016/is-there-any-way-to-test-my-conversions-to-avoid-using-exceptions-c – Alain Oct 25 '11 at 14:40

3 Answers3

8

There is no way to rethrow an exception from an outer catch block inside an inner catch block. The best way to achieve this pattern is to note whether or not the inner operation succeeded

catch (InvalidCastException e) {
  bool threw = false;
  try {
    ...
  } catch { 
    threw = true;
  }
  if (threw) {
    throw;
  }
}
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
1

If you are intending to make multiple attempts at conversion then it certainly makes sense to use non-throwing operations where applicable so that you sidestep the problem entirely.

Supposing that's not possible for the sake of argument, the next step is to question the throw e; approach. In the example code you give, IMHO there is no problem at all if your throw resets the call stack. Once someone gets to the source code for this method (which the modified call stack would still point to), I think it's pretty obvious what's going on. So while resetting the call stack is always a questionable decision, in this particular case it should be allowed to happen because there would be no tangible drawback.

Finally, the workaround you mention is interesting as well as gross (agree on that!).

Jon
  • 428,835
  • 81
  • 738
  • 806
1

I tried the following and it seems to achieve your goal, when the 2nd exception occurs (in this case, the ArgumentException) it throws the first exception (InvalidCastException)

[TestMethod]
[ExpectedException(typeof(InvalidCastException))]
public void ReThrowException() {
    var ret = false;

    try {
        ret = F1(1);
    }
    catch (InvalidCastException ex) {

        try {
            ret = F1(2);
        }
        catch (Exception e) {
            Debug.WriteLine(e.Message);
            throw ex;
        }

    }
}


private bool F1(int i) {
    if (i == 1) {
       throw new InvalidCastException();
    } else {
       throw new ArgumentException();
    }
    return false;
}

Hope this helps,

Alan.

AlanT
  • 3,627
  • 20
  • 28