Я хотел бы знать, как лучше всего избежать повторения некоторой повторяющейся структуры кода с помощью Generics Func или любым другим способом. В качестве практического примера давайте мне нужно вызвать 20 различных методов WCF, но я хотел бы иметь код для обработки исключений.
Допустим, это прокси wcf
class ClassWithMethodsToCall // say wcf proxy
{
public Out1 GetOut1(In1 inParam) { return null; } // would have some spesific implementation
public Out2 GetOut2(In2 inParam) { return null; }
public Out3 GetOut3(In3 inParam) { return null; }
}
class Out1 { } // some specific data structure
class In1 { } // some specific data structure
class Out2 { } // some specific data structure
class In2 { } // some specific data structure
class Out3 { } // some specific data structure
class In3 { } // some specific data structure
Я создал следующее, чтобы иметь одну обработку ошибок
class CallerHelperWithCommonExceptionHandler
{
public Tout Call<Tout, Tin>(Tin parameters, Func<Tin,Tout> wcfMethodToCall)
{
try
{
return wcfMethodToCall(parameters);
}
catch (Exception ex)
{
// do what ever
throw;
}
}
}
И я использую его:
var callerHelper = new CallerHelperWithCommonExceptionHandler();
var theFunctionsToCall = new ClassWithMethodsToCall();
var in1 = new In1(); // init as appropriate
var ou1 = callerHelper.Call<Out1, In1>(in1, theFunctionsToCall.GetOut1);
var in2 = new In2(); // init as appropriate
var ou2 = callerHelper.Call<Out2, In2>(in2, theFunctionsToCall.GetOut2);
// and so on
Есть ли лучший более элегантный способ? Альтернативы объектно-ориентированному подходу, шаблон проектирования шаблонов?
Спасибо, аль
Ответ 1 · рейтинг 4 · Matthew Watson
Похоже, вы добавляете код для реализации сквозной задачи в классе (например, регистрации исключений), поэтому вы можете использовать шаблон декоратора.
Например:
class Out1 { }; // some specific data structure
class In1 { } // some specific data structure
class Out2 { } // some specific data structure
class In2 { } // some specific data structure
class Out3 { } // some specific data structure
class In3 { }
internal interface IClassWithMethodsToCall
{
Out1 GetOut1(In1 inParam);
Out2 GetOut2(In2 inParam);
Out3 GetOut3(In3 inParam);
}
class ClassWithMethodsToCallImpl: IClassWithMethodsToCall
{
public Out1 GetOut1(In1 inParam) { return null; } // would have some spesific implementation
public Out2 GetOut2(In2 inParam) { return null; }
public Out3 GetOut3(In3 inParam) { return null; }
}
class ClassWithMethodsToCall: IClassWithMethodsToCall
{
private readonly ClassWithMethodsToCallImpl _impl;
public ClassWithMethodsToCall(ClassWithMethodsToCallImpl impl)
{
_impl = impl;
}
public Out1 GetOut1(In1 inParam)
{
return tryFunc(() => _impl.GetOut1(inParam));
}
public Out2 GetOut2(In2 inParam)
{
return tryFunc(() => _impl.GetOut2(inParam));
}
public Out3 GetOut3(In3 inParam)
{
return tryFunc(() => _impl.GetOut3(inParam));
}
private static T tryFunc<T>(Func<T> func)
{
try
{
return func();
}
catch (Exception exception)
{
// Do something with exception
throw;
}
}
}
Клиентский код будет использовать только IClassWithMethodsToCall, и вы, вероятно, будете использовать фабричный метод где-нибудь, который создает ClassWithMethodsToCallImpl и использует его для создания ClassWithMethodsToCall и возвращает ClassWithMethodsToCall как IClassWithMethodsToCall.
В качестве альтернативы (и, вероятно, лучше) было бы использовать аспектно-ориентированное программирование. Это требует дополнительных инвестиций и, возможно, использования сторонних библиотек для его поддержки, но, вероятно, это путь в долгосрочной перспективе.
Я заметил, что вы используете прокси-сервер WCF. Поскольку для этого используется MarshalByRefObject, вы можете использовать его для реализации АОП. Некоторая информация об этом есть в блоге здесь а>.