Страницы

Поиск по вопросам

четверг, 18 октября 2018 г.

Как обернуть много методов?

Задача следующая. Есть некий обособленный класс Test с методом TestMethod.
public Test { public void TestMethod() { //... } }
Также есть множество других классов, которые наследуются от одного абстрактного класса и в этих классах большое количество методов. Нужно, чтобы во всех этих методах сначала вызывался TestMethod(), затем шло непосредственно тело самого метода и затем снова вызывался TestMethod(), то есть:
public Class1:AbstractClass { public void Method1() { TestMethod() //тело метода TestMethod() } public void Method2() { TestMethod() //тело метода TestMethod() }
}
Понятное дело, что можно так и прописать в каждом методе каждого класса. Но может есть более изящный способ обернуть тела методов?
(!!!) Методы могут иметь разные входные и выходные параметры. Не только void и без параметров.


Ответ

Вам нужно использовать какой-нибудь AOP-фреймворк. Вот тут есть большой их список.
Давайте сделаем пример с популярным Castle.DynamicProxy
Отмечу сразу, нам нужно будет модифицировать код. Перехватываемые методы (то есть, те методы, к которым мы «добавляем» вызов TestMethod) должны быть виртуальными. Если это — слишком большое ограничение, вам понадобится другой AOP-фреймворк (например, PostSharp).
Пусть наш код такой:
class Program { static void Main(string[] args) { var derived = new Derived(); derived.M3(); } }
class Base { public void M1() { Console.WriteLine("Base::M1"); }
public int M2(int arg) { Console.WriteLine($"Base::M2, arg = {arg}"); return arg + 1; } }
class Derived : Base { public int M3() { Console.WriteLine("Derived::M3"); return M2(10); } }
и тестовый класс
class Test { public static void TestMethod(bool entry) { Console.WriteLine($"Test::TestMethod ({(entry ? "in" : "out")})"); } }
Подключим через nuget Castle.Core, и допишем наш интерсептор:
using Castle.DynamicProxy;
public class Interceptor : IInterceptor { public void Intercept(IInvocation invocation) { Test.TestMethod(); try { invocation.Proceed(); } finally { Test.TestMethod(); } } }
Затем (ограничение Castle.Proxy) нам нужно сделать наши классы публичными, а методы виртуальными. Получаем такой изменённый код:
public class Base { public virtual void M1() { Console.WriteLine("Base::M1"); }
public virtual int M2(int arg) { Console.WriteLine($"Base::M2, arg = {arg}"); return arg + 1; } }
public class Derived : Base { public virtual int M3() { Console.WriteLine("Derived::M3"); return M2(10); } }
Меняем Main
class Program { static void Main(string[] args) { var i = new Interceptor(); var proxy = new ProxyGenerator().CreateClassProxy(i); proxy.M3(); } }
Вывод программы:
Test::TestMethod (in) Derived::M3 Test::TestMethod (in) Base::M2, arg = 10 Test::TestMethod (out) Test::TestMethod (out)

Комментариев нет:

Отправить комментарий