Моя цель - иметь методы init()
и complete(result)
, которые будут работать до и после каждого метода выбранного класса. Аналогично тому, как ActionFilterAttribute
в ASP.NET имеет методы OnActionExecuting
и OnActionExecuted
, которые запускаются до и после любого метода, к которому вы их применяете.Запуск определенного метода до и после каждого вызова реализации интерфейса
Существует несколько интерфейсов. Я хотел бы применить те же методы init()
и complete(result)
, и я хочу избежать дублирования кода и упростить код, если это возможно.
Из того, что я могу сказать, похоже, нет элегантного решения. До сих пор у меня есть 3 варианта:
Вариант 1:
public interface MyImportantMethods
{
object f();
object g();
}
public class MyClass : MyImportantMethods
{
public object f()
{
// Do things
}
public object g()
{
// Do things
}
}
public class WrappedMyClass : MyImportantMethods
{
private MyImportantMethods ActualContent;
public MyModifiedClass(MyImportantMethods actualContent)
{
this.ActualContent = actualContent;
}
public object f()
{
init();
object result = this.ActualContent.f();
complete(result);
return result;
}
public object g()
{
init();
object result = this.ActualContent.g();
complete(result);
return result;
}
}
- Плюсы: Класс с реализацией полностью отделено от тот, который вызывает
init()
иcomplete()
, поэтому более читаемый и проще понять. - Против: для кого-то, не знакомого с кодом, использовать не тот. Требуется другой класс для каждого интерфейса, который я хочу использовать .
Вариант 2:
public interface MyImportantMethods
{
object f();
object g();
}
class Wrapper: IDisposable
{
public object result;
public Wrapper()
{
init();
}
void Dispose()
{
complete(result);
}
}
public class MyModifiedClass {
private void f()
{
using (var wrapper = new Wrapper(() => completeF()))
{
// Do Things
wrapper.result = result;
}
}
private void g()
{
using (var wrapper = new Wrapper(() => completeG()))
{
// Do Things
wrapper.result = result;
}
}
}
Плюсы: Не возможно использовать неправильный класс. Может быть, можно использовать один IDisposable класс для всех интерфейсов, если я использую это отражение трюк
Минусы: Код будет выглядеть гораздо более суматоху и трудно понять, для нового читателя, особенно если декларация обертки принимает множественным строк или обертки требуется больше одного параметра из результата (оба значения верны в моем случае). Также полагается на вызывающего абонента, чтобы установить результат.
Вариант 3:
public abstract class MyImportantMethodsBase
{
public object f()
{
init();
object result = this.fImplementation();
complete(fResult);
return result;
}
public object g()
{
init();
object result = this.gImplementation();
complete(result);
return result;
}
private abstract object fImplementation();
private abstract object gImplementation();
}
public class MyModifiedClass : MyImportantMethodsBase {
private object void fImplementation()
{
// Do Things
}
private object gImplementation()
{
// Do Things
}
}
Плюсы: Не возможно использовать неправильный класс. Класс с реализацией полностью отделен от той, которая вызывает init() и complete(), поэтому она более понятна и понятна.
Против: Менее просто для чтения читателя.
Есть ли действительно никакого способа, как просто и понятно, как ActionFilterAttribute
для достижения своей цели?
ИМХО, вариант номер 3 является лучшим, и я не считаю, что это трудно понять. Как вы указываете ActionFilterAttribute, почему бы не создать атрибут и не использовать его в своих классах? – Skaparate
Мне также нравится Option3: пример шаблона шаблона шаблона, который многие программисты распознают – alexm
@Skaparate вам нужно что-то, что будет использовать атрибуты - вы не можете ожидать, что только добавление атрибутов пары будет волшебным образом реализовать перехват метода/интерфейса, доступный в большинстве контроллеры инъекций. Если вас интересует то, что OP, вероятно, пытается сделать, вы можете проверить, как это делается с Unity (https://msdn.microsoft.com/en-us/library/dn178466(v=pandp.30).aspx) или вообще https://www.bing.com/search?q=c%23%20dependency%20injection%20interception –