Еще Один Аоп В .Net

Многие .

NET-разработчики, использовавшие в своей практике WPF, Silverlight или Metro UI, так или иначе задавались вопросом «как можно упростить реализацию интерфейса INotifyPropertyChanged и свойств, об изменениях которых нужно сигнализироватьЭ» Самый простой «классический» вариант описания свойства, поддерживающего уведомление о его изменении, выглядит так:

  
  
  
  
  
   

public string Name { get { return _name; } set { if(_name != value) { _name = value; NotifyPropertyChanged(“Name”); } } }

Чтобы избежать повторения одинаковых строк в каждом сеттере, можно создать вспомогательную функцию.

Более того, начиная с .

NET 4.5, в нем можно использовать атрибут [CallerMemberName], чтобы не указывать явно имя вызывающего его свойства.

Но это не решает главную проблему — все равно для каждого нового свойства необходимо явно описывать поле и геттер с сеттером.

Такая механическая работа неинтересна, утомительна и может привести к ошибкам копирования и вставки.

Хотелось бы немного «волшебства», которое позволило бы без особых усилий (например, одной строчки кода) сделать такой класс совместимым с INotifyPropertyChanged:

public class Person { public string FirstName { get; set; } public string LastName { get; set; } public DateTime Birth { get; set; } }

Надо отметить, что это не единственная задача, в которой хотелось бы облегчить себе жизнь при добавлении сквозного функционала.

Типичные задачи логирования вызовов методов определенного класса, измерения времени их выполнения, проверки наличия прав на вызов — это все, что требует общего решения, исключающего необходимость вводить одинаковые куски кода везде, где это необходимо.

Более-менее опытный разработчик сразу скажет: «Это аспектно-ориентированное программирование!» и он будет прав.

А если начать перечислять уже существующие библиотеки для платформы .

NET, в которых в той или иной степени можно использовать АОП, то список будет не таким коротким: PostSharp, Unity, Spring .

NET, Castle Windsor, Aspect. NET. И это еще не все, но здесь следует задуматься о механизмах, реализующих вставку сквозного функционала, об их преимуществах и недостатках.

Есть два основных способа:

  • Замена во время компиляции (PostSharp)
  • Генерация прокси-классов во время выполнения (Unity, Spring .

    NET, Castle Windsor)

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

Обычная генерация прокси-классов хоть и проще в реализации, но, помимо вычислительных затрат, имеет и ограничения — методы или свойства должны содержаться в интерфейсе или быть виртуальными, чтобы их можно было перехватить через прокси-класс.

PostSharp предлагает очень большие возможности для использования аспектно-ориентированного программирования, но это коммерческий продукт, который может быть неприемлем для многих проектов.

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

Самый простой пример использования Aspect Injector — журналирование вызовов методов.

Сначала нужно описать класс аспекта:

public class MethodTraceAspect { [Advice(InjectionPoints.Before, InjectionTargets.Method)] public void Trace([AdviceArgument(AdviceArgumentSource.TargetName)] string methodName) { Console.WriteLine(methodName); } }

В этом описании сказано, что при применении этого аспекта к любому другому классу вызов Trace() будет добавлен в начале каждого из его публичных методов с именем самого метода в качестве параметра.



[Aspect(typeof(MethodTraceAspect))] public class Target { public void Create() { /* … */ } public void Update() { /* … */ } public void Delete() { /* … */ } }

После такого объявления Create, Update, Delete будут выводить свои имена на консоль каждый раз при их вызове.

Следует отметить, что атрибут Aspect можно применять не только к классам, но и к конкретным членам класса, если необходима «точечная вставка».

Вот пример декомпилированного кода, полученного после компиляции примера выше:

public class Target { private readonly MethodTraceAspect __a$_MethodTraceAspect; public void Create() { this.__a$_MethodTraceAspect.Trace("Create"); } public void Update() { this.__a$_MethodTraceAspect.Trace("Update"); } public void Delete() { this.__a$_MethodTraceAspect.Trace("Delete"); } public Target() { this.__a$_MethodTraceAspect = new MethodTraceAspect(); } }

Здесь вы также заметите, что атрибут Aspect был удален во время генерации кода, что позволило полученной сборке не ссылаться на сборку Aspect Injector. Если вернуться к исходной задаче реализации интерфейса INotifyPropertyChanged, то с помощью Aspect Injector можно создать и успешно использовать следующий аспект:

[AdviceInterfaceProxy(typeof(INotifyPropertyChanged))] public class NotifyPropertyChangedAspect : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged = (s, e) => { }; [Advice(InjectionPoints.After, InjectionTargets.Setter)] public void RaisePropertyChanged( [AdviceArgument(AdviceArgumentSource.Instance)] object targetInstance, [AdviceArgument(AdviceArgumentSource.TargetName)] string propertyName) { PropertyChanged(targetInstance, new PropertyChangedEventArgs(propertyName)); } }

Для всех общедоступных свойств всех классов, к которым будет привязан этот аспект, в конце установщика будет выполнен RaisePropertyChanged. Более того, интерфейс, указанный в атрибуте AdviceInterfaceProxy, будет добавлен в класс самим фреймворком во время компиляции.

На страница проекта Вы можете найти более подробную информацию об атрибутах и их параметрах, доступных на данный момент. Будем благодарны за любые отзывы и предложения по развитию Aspect Injector! Теги: #.

NET #aop #программирование #.

NET

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.