• Авторизация


Упрощаем жизнь или PostSharp это наше фсё ;) 23-11-2007 18:40 к комментариям - к полной версии - понравилось!


Есть такой продукт PostSharp , предназначен для трансформации IL-кода на лету. Вот хочу показать жизненный пример использования. В .NET 3.0 (а точнее в WPF) появилось понятие DependencyProperty. Это такие "волшебные" свойства которые, например, могут участвовать в DataBinding, "наследовать" свои значения по иерархии вложенных экземпляров и.т.п. К сожалению добавлять свои DependencyProperty достаточно громоздко и можно легко ошибится, посмотрите пример ClassicImplementation (строки 10-37). С использованием PostSharp все стало значительно компактнее и прозрачнее, смотрите NewImplementation (строки 39-57).

Ну и основное "волшебство" заключено в классе DependencyPropertyAttribute который подменяет реализацию геттеров/сеттеров свойств ;) (строки 61-226)

    1 using System;
    2 using System.Collections.Generic;
    3 using System.Reflection;
    4 using System.Windows;
    5 using PostSharp.Extensibility;
    6 using PostSharp.Laos;
    7 
    8 namespace PostSharpDemo
    9 {
   10     /// <summary>
   11     /// Классическая реализация 2-х свойств
   12     /// </summary>
   13     public class ClassicImplementation: DependencyObject
   14     {
   15         public static readonly DependencyProperty DemoStringProperty =
   16             DependencyProperty.Register(
   17                 "DemoString",
   18                 typeof (string), typeof (ClassicImplementation),
   19                 new PropertyMetadata("Default String Value"));
   20         public static readonly DependencyProperty DemoInt32Property =
   21             DependencyProperty.Register(
   22                 "DemoInt32",
   23                 typeof(string), typeof(ClassicImplementation),
   24                 new PropertyMetadata(0));
   25 
   26         public int DemoInt32
   27         {
   28             get { return (int) GetValue(DemoInt32Property); }
   29             set { SetValue(DemoInt32Property, value); }
   30         }
   31 
   32         public string DemoString
   33         {
   34             get { return (string)GetValue(DemoStringProperty); }
   35             set { SetValue(DemoStringProperty, value); }
   36         }
   37     }
   38 
   39     /// <summary>
   40     /// А вот с использованием PostSharp
   41     /// </summary>
   42     public class NewImplementation: DependencyObject
   43     {
   44         [DependencyProperty(0)]
   45         public int DemoInt32
   46         {
   47             get { throw new NotImplementedException(); }
   48             set { throw new NotImplementedException(); }
   49         }
   50 
   51         [DependencyProperty("Default String Value")]
   52         public string DemoString
   53         {
   54             get { throw new NotImplementedException(); }
   55             set { throw new NotImplementedException(); }
   56         }        
   57     }
   58 
   59 
   60 
   61     /**************************************************************
   62       Вот тут всё "колдунство"
   63      *************************************************************/ 
   64 
   65     /// <summary>
   66     /// Магический аттрибут, превращающий свойство в DependencyProperty
   67     /// ВНИМАНИЕ! реализация свойства полностью замещается!
   68     /// </summary>
   69     [Serializable, MulticastAttributeUsage(MulticastTargets.Property)]
   70     public sealed class DependencyPropertyAttribute: CompoundAspect
   71     {
   72         private object defaultValue = null;
   73         /// <summary>
   74         /// Значение по умолчанию
   75         /// </summary>
   76         public object DefaultValue{ get { return defaultValue; } }
   77         /// <summary>
   78         /// Конструирует аттрибут
   79         /// </summary>
   80         /// <param name="defaultValue">Значение свойства по умолчанию</param>
   81         public DependencyPropertyAttribute(object defaultValue)
   82         {
   83             this.defaultValue = defaultValue;
   84         }
   85 
   86         /// <summary>
   87         /// Проверка допустимости применения аспекта
   88         /// </summary>
   89         /// <param name="element">цель аспекта</param>
   90         /// <returns>допустимость применения аспекта</returns>
   91         public override bool CompileTimeValidate(object element)
   92         {
   93             if(!base.CompileTimeValidate(element))
   94                 return false;
   95             PropertyInfo pi = element as PropertyInfo;
   96             if(pi==null)
   97                 return false;
   98             if(!typeof(DependencyObject).IsAssignableFrom(pi.DeclaringType))
   99                 return false;
  100             if(!pi.CanRead || !pi.CanWrite)
  101                 return false;
  102             if(pi.GetSetMethod().IsStatic || pi.GetGetMethod().IsStatic)
  103                 return false;
  104             return true;
  105         }
  106 
  107         /// <summary>
  108         /// Заполнение коллекции аспектов
  109         /// </summary>
  110         /// <param name="element">цель аспекта</param>
  111         /// <param name="c">набор аспектов</param>
  112         public override void ProvideAspects(object element, LaosReflectionAspectCollection c)
  113         {
  114             PropertyInfo pi = (PropertyInfo) element;
  115             c.AddAspect(pi.GetSetMethod(), new MyAspect(pi, false, this));
  116             c.AddAspect(pi.GetGetMethod(), new MyAspect(pi, true, this));
  117         }
  118 
  119         private static readonly object lockObject = new object();
  120         private static readonly Dictionary<PropertyInfo, DependencyProperty> dictionary
  121             = new Dictionary<PropertyInfo, DependencyProperty>();
  122 
  123         /// <summary>
  124         /// Регистрация/поиск DependencyProperty
  125         /// </summary>
  126         /// <param name="pi">свойство</param>
  127         /// <returns>экземпляр DependencyProperty</returns>
  128         private DependencyProperty registerProperty(PropertyInfo pi)
  129         {
  130             lock(lockObject)
  131             {
  132                 DependencyProperty value;
  133                 if (dictionary.TryGetValue(pi, out value))
  134                     return value;
  135                 else
  136                 {
  137                     PropertyMetadata propertyMetadata;
  138                     propertyMetadata = new PropertyMetadata(DefaultValue);
  139                     DependencyProperty dependencyProperty =
  140                         DependencyProperty.Register(pi.Name,
  141                                                     pi.PropertyType, pi.DeclaringType,
  142                                                     propertyMetadata);
  143                     dictionary.Add(pi, dependencyProperty);
  144                     return dependencyProperty;
  145                 }
  146             }
  147         }
  148 
  149         /// <summary>
  150         /// Поиск DependencyProperty
  151         /// </summary>
  152         /// <param name="pi">свойство</param>
  153         /// <returns>экземпляр DependencyProperty</returns>
  154         public static DependencyProperty Get(PropertyInfo pi)
  155         {
  156             lock(lockObject)
  157             {
  158                 DependencyProperty value;
  159                 if(dictionary.TryGetValue(pi, out value))
  160                     return value;
  161                 else
  162                     return null;
  163             }
  164         }
  165 
  166         /// <summary>
  167         /// Поиск DependencyProperty
  168         /// </summary>
  169         /// <param name="type">тип - владелец свойства</param>
  170         /// <param name="Name">наименование свойства</param>
  171         /// <returns>экземпляр DependencyProperty</returns>
  172         public static DependencyProperty Get(Type type, string Name)
  173         {
  174             PropertyInfo pi = type.GetProperty(Name, BindingFlags.Public | BindingFlags.Instance);
  175             return Get(pi);
  176         }                
  177 
  178         /// <summary>
  179         /// Непосредственно аспект, заменюющий реализацию Get/Set для свойства
  180         /// </summary>
  181         [Serializable]
  182         private sealed class MyAspect : ImplementMethodAspect
  183         {
  184             private readonly PropertyInfo pi;
  185             private bool outDirection;
  186             [NonSerialized]    private DependencyProperty prop;
  187             private DependencyPropertyAttribute parent;
  188 
  189             /// <summary>
  190             /// Конструктор
  191             /// </summary>
  192             /// <param name="pi">свойство к которому применён аспект</param>
  193             /// <param name="outDirection">если true то замещаем Get иначе замещаем Set</param>
  194             /// <param name="parent"></param>
  195             public MyAspect(PropertyInfo pi, bool outDirection, DependencyPropertyAttribute parent)
  196             {
  197                 this.pi = pi;
  198                 this.outDirection = outDirection;
  199                 this.parent = parent;
  200             }
  201 
  202             /// <summary>
  203             /// Инициализация рантайма после десериализации
  204             /// </summary>
  205             /// <param name="method"></param>
  206             public override void RuntimeInitialize(MethodBase method)
  207             {
  208                 base.RuntimeInitialize(method);
  209                 // регистрируем Dependency свойство
  210                 // делаем это в тут а не в конструкторе потому что в Runtime
  211                 // конструктор не вызывается
  212                 prop = parent.registerProperty(pi);
  213             }
  214 
  215             /// <summary>
  216             /// Замещение реализации
  217             /// </summary>
  218             /// <param name="e"></param>
  219             public override void OnExecution(MethodExecutionEventArgs e)
  220             {
  221                 if(outDirection)
  222                     e.ReturnValue = ((DependencyObject)e.Instance).GetValue(prop);
  223                 else
  224                     ((DependencyObject)e.Instance).SetValue(prop, e.GetArguments()[0]);
  225             }
  226         }
  227     }
  228 }
вверх^ к полной версии понравилось! в evernote
Комментарии (3):
12-03-2009-17:34 удалить
Ну, во-первых реализация методов не нужна, то есть можно просто { get; set;}, во-вторых можно было бы лок получше сделать, ReaderWriterLockSlim. В третьих в сете свойства используется функция ПостШарпа которая уже устарела. Ну и так далее...
06-09-2009-17:09 удалить
здесь Лик Стража Смерти
слабонервным делать нечего
в глаза не смотреть !
Мощнейший гипноз


Комментарии (3): вверх^

Вы сейчас не можете прокомментировать это сообщение.

Дневник Упрощаем жизнь или PostSharp это наше фсё ;) | dimzon541 - Поток не замутненного разумом сознания... | Лента друзей dimzon541 / Полная версия Добавить в друзья Страницы: раньше»