2008-11-19 2 views
2

Предположим, у меня есть сборка .NET, которая использует отражение для загрузки сборок B и C (также .NET). Эти две сборки реализуют множество больших интерфейсов (то же самое для обоих). Когда метод вызывается в A, он пытается заставить B выполнить работу. Однако B ненадежен и может вызывать исключения. В настоящее время A имеет два режима: один, где он распространяет исключения для вызывающего абонента A и один, где он называет методы сопоставления более стабильным (но менее эффективным) C.Унифицированная обработка ошибок больших интерфейсов

Существуют ли более эффективные способы (меньше кода) для реализации этот сценарий, чем обертывание всех методов B, демонстрирует огромную реализацию всех интерфейсов B, только теперь окружающих каждый вызов кодом, как показано ниже? Компоненты B и C ничего не знают о выбранном методе обработки ошибок, поэтому они не могут реализовать логику.

public class BErrorWrapper : I1, I2, I3{ 
    ... 
    public int DoSomeWork(int num){ 
     if (FailWithExceptions) 
     { 
     try 
     { 
      return B.DoSomeWork(num); 
     } 
     catch(MyLibException e) 
     { 
      return C.DoSomeWOrk(num); 
     } 
     } 
     else 
     { 
     return B.DoSomeWork(num); 
     } 
    } 
    ... 
} 

ответ

2

Вы можете сделать это, он сохраняет некоторые повторения:

public class BErrorWrapper : I1, I2, I3{ 
    ... 
    public int DoSomeWork(int num){ 
     try 
     { 
     return B.DoSomeWork(num); 
     } 
     catch(MyLibException e) 
     { 
     if (FailWithExceptions) throw; 
     return C.DoSomeWOrk(num); 
     } 
    } 
    ... 
} 
1

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

static void TryWithFallback<T>(Action<T> primary, Action<T> fallback, T arg) 
    { 
     try 
     { 
      primary(arg); 
     } 
     catch // add your other regular code here... 
     { 
      fallback(arg); 
     } 
    } 

Тогда вы можете повторно использовать это для реализации через:

TryWithFallback(b.DoSomeWork, c.DoSomeWork, num); 

Очевидно, что вы могли бы добавить несколько подписей для соответствующего кода, такие как:

static TResult TryWithFallback<T, TResult>(Func<T, TResult> primary, Func<T, TResult> fallback, T arg) 
    { 
     try 
     { 
      return primary(arg); 
     } 
     catch 
     { 
      return fallback(arg); 
     } 
    } 
1

Я предлагаю вам взглянуть на использование отражения и System.CodeDom для генерации кода. У меня была аналогичная проблема в последнее время, когда я пытался написать оболочку для сборки COM-взаимодействия, которая имела очень большой интерфейс с множеством методов с сигнатурами, которые содержали типы параметров, которые я не хотел использовать на стороне клиента, но которые я мог легко конвертировать в те типы, которые я действительно хотел на стороне клиента. Они также были параметрами «ref», которые сделали бы код клиента более подробным. Методы имели различное количество параметров со значимыми именами, которые я хотел выставить на стороне клиента.

Напишите базовый класс для вашей оболочки, в котором есть члены для экземпляра A и B. Напишите класс генерации кода, который генерирует производный класс-оболочку. Генерация кода должна затем перебирать методы для каждого интерфейса, которые должна быть реализована оболочкой, и добавить тело метода и метода с соответствующим кодом для вызова A и B в вашей необходимой конструкции обработки ошибок. Код, который вы генерируете для вызова A и B, будет зависеть от сигнатуры метода, который вы вызываете, но этого не сложно достичь, итерации по этим параметрам генерируемого или вызываемого метода.

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

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

Смежные вопросы