Лог поймал исключения из-за пределов метода, в котором они были пойманы
У меня есть метод вроде:
public TResult DoSomethingWithLogging<TResult>(Func<TResult> someAction)
{
try
{
return someAction.Invoke();
}
catch (Exception ex)
{
LogException(ex)
throw;
}
Этот метод используется следующим образом:
var result = DoSomethingWithLogging(() => Foo());
Я также хочу записывать исключения, которые были обнаружены внутри Foo()
. Я не могу использовать throw
в catch
внутри Foo
.
Как я могу поймать такие исключения?
Пример:
public static string Foo()
{
try
{
return "Foo";
}
catch (Exception)
{
// I have to log this exception too without adding anything to Foo
return "Exception caught";
}
}
Ответы
Ответ 1
Вы можете привязываться к событию FirstChanceException
. Здесь ваш код изменился, чтобы продемонстрировать это:
using System;
using System.Runtime.ExceptionServices;
public class Program
{
public static void Main()
{
AppDomain.CurrentDomain.FirstChanceException +=
(object source, FirstChanceExceptionEventArgs e) =>
{
Console.WriteLine("FirstChanceException event raised in {0}: {1}",
AppDomain.CurrentDomain.FriendlyName, e.Exception.Message);
};
Console.WriteLine("Hello World");
Console.WriteLine(DoSomethingWithLogging(() => Foo()));
}
public static TResult DoSomethingWithLogging<TResult>(Func<TResult> someAction)
{
try
{
return someAction.Invoke();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
public static string Foo()
{
try
{
throw new Exception("This will be caught");
return"Foo";
}
catch (Exception) //I have to log this exception too without adding anything too Foo
{
return "Exception caught";
}
}
}
Как правило, я бы очень осторожно относился к этому ни в чем другом, кроме сценариев отладки. Как только это поймано, это не должно рассматриваться как исключение по коду выше. (Конечно, ловить его в первую очередь могло быть логической ошибкой, поэтому это действительно имеет некоторое значение в сценариях отладки).
Есть также осложнения в многопоточных случаях. В приведенном выше коде демонстрируется, как работает FirstChanceException
, но если вы подключили его до вызова и затем отсоединили после того, как он все равно будет запускаться из-за каких-либо исключений из других потоков. Фильтрация этих данных может быть сложной. Вероятно, я начну с рассмотрения взгляда на стек вызовов, но я не уверен, что лучший способ.
Ответ 2
Вы можете сделать это, обратив внимание на AppDomain.FirstChanceException
событие:
Возникает, когда в управляемом коде создается исключение, прежде чем среда выполнения ищет стек вызовов для обработчика исключений в домене приложения.
См. Исключение исключений первого шанса в управляемом коде без отладки.
Ответ 3
Я думаю, вы идете по этому пути неправильно. Это очень плохая идея предположить что-то о реализации foo. (Подобно JDM, упомянутому в комментариях, это запах кода, и это приведет вас в неприятности)
Один из способов редизайна вашего подхода - использовать события
class FooClass {
public event SkippedWorkEventHandler SkippedWork;
public void Foo() {
try {
/* some code */
} catch (Exception ex) {
if (SkippedWork != null) {
/* pass in the relevant data to eventargs */
SkippedWork(this, EventArgs.Empty)
}
}
}
public void DoSomethingWithFoo() {
SkippedWork += new LogSkippedWorkEventHandler
try {
Foo()
} catch (Exception ex) {
/*handle uncaughed exceptions here */
}
}
}
Причина этого в том, что со стороны я не буду гарантировать, что я использую try/catch, чтобы обнаружить, что происходит внутри foo. я могу переписать его на простой, если проверить и вернуть, если мой тест не удастся. Результат foo будет таким же, но теперь ваши исключения не регистрируются.
Выставляя событие, вы позволяете кому-либо из узида, который интересуется определенными вещами (пропущенная строка на основе вашего комментария), реагировать на нее. и вы заключили договор, в котором говорится, что вы будете отмечать/поднимать это событие.