, предназначен для трансформации IL-кода на лету. Вот хочу показать жизненный пример использования. В .NET 3.0 (а точнее в
. Это такие "волшебные" свойства которые, например, могут участвовать в 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 }