Как восстановить предыдущее исключение из встроенного блока try-catch? (С#)

У меня есть код, который пытается преобразовать тип. Если он терпит неудачу, я хочу попробовать что-то еще, и если это также не удастся, повторите первоначальное исключение, предпринятое первым преобразованием. Проблема заключается в том, что единственный способ, которым я знаю, - это "throw;", сидящий в конце блока catch. Что происходит, когда я хочу, чтобы ретроп произошел из другого блока catch?

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; }
}

Как вы можете видеть выше, я должен использовать 'throw e;', который сбрасывает стек вызовов.

Только обходной путь, который я имею до сих пор (imo):

bool handled = true;
... 
catch { handled = false; }
if( !handled ) throw;

Ответ 1

Невозможно восстановить исключение из внешнего блока catch внутри блока catch inner. Лучший способ добиться этого шаблона - отметить, выполнялась ли внутренняя операция

catch (InvalidCastException e) {
  bool threw = false;
  try {
    ...
  } catch { 
    threw = true;
  }
  if (threw) {
    throw;
  }
}

Ответ 2

Если вы намерены совершать несколько попыток конверсии, то, безусловно, имеет смысл использовать операции без металирования, где это применимо, чтобы полностью обойти проблему.

Предполагая, что это невозможно для аргументации, следующим шагом будет вопрос о подходе throw e;. В приведенном ниже примере кода IMHO нет проблем, если ваш throw сбрасывает стек вызовов. Как только кто-то попадает в исходный код этого метода (к которому все еще должен был обратиться модифицированный стек вызовов), я думаю, что это довольно очевидно, что происходит. Поэтому, когда сброс стека вызовов всегда является сомнительным решением, в этом конкретном случае это должно быть разрешено, потому что не было бы ощутимого недостатка.

Наконец, обходной путь, о котором вы упоминаете, интересен и важен (согласитесь с этим!).

Ответ 3

Я попробовал следующее и, похоже, достиг своей цели, когда возникает второе исключение (в данном случае ArgumentException), он генерирует первое исключение (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;
}

Надеюсь, что это поможет,

Алан.