Как избавиться от попытки поймать?

Мне скучно с окружающим кодом с попыткой поймать вот так.

try
{
    //some boring stuff
}
catch(Exception ex)
{
    //something even more boring stuff
}

Мне хотелось бы что-то вроде

SurroundWithTryCatch(MyMethod)

Я знаю, что могу выполнить это поведение, создав делегата с точной подписью функции, но создав делегат для всех методов в моем приложении, это просто не вариант.

Я также могу это сделать, введя IL-код, но это дорого с точки зрения производительности, поскольку он создает сборку оболочки вокруг моей.

Любые другие действительные идеи?

Ответ 1

Во-первых, похоже, что вы слишком часто используете try/catch - особенно если вы ловите Exception. блоки try/catch должны быть относительно редкими; если вы не сможете "обработать" исключение, вы должны просто позволить ему перейти на следующий уровень стека.

Теперь, если вы действительно хотите все эти блоки try/catch, почему это не вариант создания делегата? С анонимными методами и лямбда-выражениями, а также с делегатами Func/Action в пространстве имен System в основном очень мало работы. Вы пишете:

public void SurroundWithTryCatch(Action action)
{
    try
    {
        action();
    }
    catch(Exception ex)
    {
        //something even more boring stuff
    }    
}

а затем ваш SurroundWithTryCatch(MyMethod) будет работать нормально, если он не принимает параметров.

В качестве альтернативы, если вы не хотите вызывать другой метод, просто напишите:

public void MyMethod()
{
    SurroundWithTryCatch(() => 
    {
        // Logic here
    });
}

Если вам нужно вернуться из метода, вы можете сделать:

public int MyMethod()
{
    return SurroundWithTryCatch(() => 
    {
        // Logic here
        return 5;
    });
}

с общей перегрузкой SurroundWithTryCatch следующим образом:

public T SurroundWithTryCatch<T>(Func<T> func)
{    
    try
    {
        return func();
    }
    catch(Exception ex)
    {
        //something even more boring stuff
    }    
}

В С# 2 все будет хорошо, но вывод типа вам не поможет, и вам придется использовать анонимные методы вместо лямбда-выражений.

Вернемся к началу: старайтесь чаще использовать try/catch. (try/finally должен быть намного более частым, хотя обычно он написан как оператор using.)

Ответ 3

Вместо этого вы можете попытаться использовать некоторую нулевую проверку. Я могу взять пример LINQ to SQL:

var user = db.Users.SingleOrDefault(u => u.Username == 3);

if (user == null)
    throw new ArgumentNullException("User", "User cannot be null.");

// "else" continue your code...

Ответ 4

Возможно, вы обрабатываете обработку исключений как коды ошибок с помощью другого синтаксиса? Так что не пытайтесь/поймать. Пусть исключение распространяется вверх.

Ответ 5

Для меня, похоже, вы просите аспектно-ориентированное программирование. Я думаю, вам стоит взглянуть на PostSharp.

Ответ 6

Я не уверен в С#, но в Java-land вы можете определить и связать все методы, а затем скрыть его под прокси-объектом. Вы можете сбежать с написанием еще большего кода, определив что-то вроде:

ExceptionCatcher.catchAll(new Runnable() {
  public void run() {
     //run delegate here
     MyMethod();
  }
});

и catchAll() просто вызовет runnable и обернет вокруг него блок try-catch.

Однако, я думаю, что вы действительно хотите, это язык, который получил закрытие поддержки. Используя закрытие, делать то, что вы хотите, очень легко.

Ответ 7

Если вы используете Java, у вас есть RuntimeExceptions, которые являются исключениями, которые означают, что что-то пошло не так, от чего нельзя ожидать восстановления. Поищи это. Начать здесь: http://java.sun.com/docs/books/tutorial/essential/exceptions/runtime.html

Например, Spring бит доступа к данным генерируют различные RuntimeExceptions, когда все идет не так. Работа с ними необязательна.