Страницы

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

пятница, 13 декабря 2019 г.

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

#c_sharp


Задача следующая.
Есть некий обособленный класс Test с методом TestMethod.

public Test
{
    public void TestMethod()
    {
    //...
    }
}


Также есть множество других классов, которые наследуются от одного абстрактного класса
и в этих классах большое количество методов. 
Нужно, чтобы во всех этих методах сначала вызывался TestMethod(), затем шло непосредственно
тело самого метода и затем снова вызывался TestMethod(), то есть:

public Class1:AbstractClass
{
    public void Method1()
    {
         TestMethod()
         //тело метода
         TestMethod()
    }
    public void Method2()
    {
         TestMethod()
         //тело метода
         TestMethod()
    }

}


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

(!!!) Методы могут иметь разные входные и выходные параметры. Не только void и без
параметров.
    


Ответы

Ответ 1



Вам нужно использовать какой-нибудь 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)

Ответ 2



Как насчёт using? Хотя это и не очень-то корректно семантически: public void Method1(){ using (new TestMethodWrapper()){ //тело метода } } public class TestMethodWrapper : IDisposable { public TestMethodWrapper(){ TestMethod(); } public void Dispose(){ TestMethod(); } }

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

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