Как я могу добавить общую функциональность вокруг вызовов методов? - PullRequest
2 голосов
/ 17 декабря 2010

Код, о котором идет речь, написан роботом (CodeSmith), и его трудно поддерживать.Это выглядит примерно так:

public AddressProgramTemplate GetById(System.Int32 _id) {
    try {
        return Service.GetById(_id);
    } catch (FaultException<ErrorInfo> ex) {
        throw new ProxyServerBusinessException(ex.Detail);
    } catch (FaultException) {
        throw new ProxyServerBusinessException(null);
    } catch (EndpointNotFoundException ex) {
        throw new ProxyServerTechnicalException<EndpointNotFoundException>(ex);
    } catch (CommunicationObjectFaultedException ex) {
        throw new ProxyServerTechnicalException<CommunicationObjectFaultedException>(ex);
    } catch (CommunicationException ex) {
        throw new ProxyServerTechnicalException<CommunicationException>(ex);
    } catch (ObjectDisposedException ex) {
        throw new ProxyServerTechnicalException<ObjectDisposedException>(ex);
    } catch (TimeoutException ex) {
        throw new ProxyServerTechnicalException<TimeoutException>(ex);
    }
}

Как вы можете догадаться, это код прокси WCF на стороне клиента, и все эти строки повторяются для каждого метода обслуживания (и их много).Что хорошо для робота, так это печаль для меня, поэтому я начал его реорганизовывать.Прежде всего, логика и обработка исключений делегируются в Microsoft Enterprise Library, а общий код переносится в базовый класс:

public TResult WrapServiceMethod<TResult>(Func<TResult> serviceMethod) {
    TResult result = default(TResult);
    try {
        result = serviceMethod();
    } catch (Exception ex) {
        bool rethrow = ExceptionManager.HandleException(ex, ExceptionPolicyNames.ClientRequestPolicy);
        if (rethrow) throw;
    }
    return result;
}

Пока все хорошо, уродливая куча try / catch превращается в аккуратную строку:

return WrapServiceMethod<AddressProgramTemplate>(() => Service.GetById(_id));

Немного усилий и пустых методов.Проблема возникает, когда вызовы службы используют out параметры:

public void GetPeriod(AddressProgram program, out DateTime startDate, out DateTime endDate){
    WrapServiceMethod(() => Service.GetPeriod(program, out startDate, out endDate));
}

В результате " Невозможно использовать параметр refDate или out 'endDate' внутри анонимного метода, лямбда-выражения или выражения запроса "и я понимаю почему .

В идеале мне бы хотелось иметь возможность определять пользовательские блоки операторов, такие как while () или using (), чтобы я мог написать

wrapexception { ... }

и жить долго и счастливо, но я не думаю, что этот трюк возможен с .NET.Предполагая, что переписывание всех методов обслуживания без параметров out является последним средством, есть ли у меня какие-либо другие варианты?

Ответы [ 2 ]

2 голосов
/ 17 декабря 2010

Звучит так, будто вы ищете библиотеку аспектно-ориентированного программирования, такую ​​как PostSharp.

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

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

Взгляните на пример на http://www.sharpcrafters.com/solutions/monitoring#exception-monitoring, который показывает, как обрабатывать исключения.

1 голос
/ 17 декабря 2010

Альтернатива изменению подписей out (и, следовательно, необходимость изменения всего вызывающего кода, который, я уверен, вы хотите избежать), вы могли бы сделать что-то вроде этого:

...