public class WorkerThreadAttribute : OnMethodInvocationAspect<br/>
{<br/>
public override void OnInvocation(MethodInvocationEventArgs eventArgs)<br/>
{<br/>
ThreadPool.QueueUserWorkItem(state => eventArgs.Proceed());<br/>
}<br/>
}<br/>
It is interesting that you can call such code and get the return value without any type conversions, as when using QueueUserWorkItem
directly.public class FormsThreadAttribute : OnMethodInvocationAspect<br/>
{<br/>
public override void OnInvocation(MethodInvocationEventArgs eventArgs)<br/>
{<br/>
Form f = (Form)eventArgs.Instance;<br/>
if (f.InvokeRequired)<br/>
f.Invoke(eventArgs.Delegate, eventArgs.GetArgumentArray());<br/>
else <br/>
eventArgs.Proceed();<br/>
}<br/>
}<br/>
... so in WPF:public class WpfThreadAttribute : OnMethodInvocationAspect<br/>
{<br/>
private DispatcherPriority priority;<br/>
public WpfThreadAttribute() : this (DispatcherPriority.Normal) { }<br/>
public WpfThreadAttribute(DispatcherPriority priority)<br/>
{<br/>
this .priority = priority;<br/>
}<br/>
public override void OnInvocation(MethodInvocationEventArgs eventArgs)<br/>
{<br/>
DispatcherObject dispatcherObject = (DispatcherObject)eventArgs.Instance;<br/>
if (dispatcherObject.CheckAccess())<br/>
eventArgs.Proceed();<br/>
else <br/>
dispatcherObject.Dispatcher.Invoke(priority, new Action(eventArgs.Proceed));<br/>
}<br/>
}<br/>
In the latter case, we even have the opportunity to set the priority of execution.set
/ get
methods is domain-specific, but there is one aspect that is sometimes useful to “pull out” - these are the notification notification settings - something called property change notification. In WinForms, we have the INotifyPropertyChanged
interface INotifyPropertyChanged
which sometimes is not so convenient to implement manually. Also, this interface works in WPF, but there is another alternative - the creation of a so-called. dependency property.[Serializable]<br/>
class LazyLoad : OnFieldAccessAspect<br/>
{<br/>
private readonly Type type;<br/>
private readonly object [] args;<br/>
public LazyLoad(Type type, params object [] arguments)<br/>
{<br/>
this .type = type;<br/>
args = arguments;<br/>
}<br/>
public override OnFieldAccessAspectOptions GetOptions()<br/>
{<br/>
return OnFieldAccessAspectOptions.RemoveFieldStorage;<br/>
}<br/>
public override void OnGetValue(FieldAccessEventArgs eventArgs)<br/>
{<br/>
if (eventArgs.StoredFieldValue == null )<br/>
eventArgs.StoredFieldValue = Activator.CreateInstance(type, args);<br/>
eventArgs.ExposedFieldValue = eventArgs.StoredFieldValue;<br/>
}<br/>
}<br/>
Unfortunately, this code contains a not very neat implementation (the type of the object is transferred to the constructor), but on the other hand, this implementation provides additional flexibility. And of course, no one bothers to cause, say, My.IoCContainer.Resolve
, bypassing the traditional DI model in which “everything at once” is issued instead of Activator.CreateInstance
.[Serializable]<br/>
public class RetryAttribute : OnMethodInvocationAspect<br/>
{<br/>
public int Count { get; set; }<br/>
public int DelayMsec { get; set; }<br/>
public RetryAttribute( int count) : this (count, 0) { }<br/>
public RetryAttribute( int count, int delayMsec)<br/>
{<br/>
Count = count;<br/>
DelayMsec = delayMsec;<br/>
}<br/>
public override void OnInvocation(MethodInvocationEventArgs eventArgs)<br/>
{<br/>
for ( int a = 0; ; ++a)<br/>
{<br/>
try <br/>
{<br/>
if (a != 0 && DelayMsec > 0)<br/>
Thread.Sleep(DelayMsec);<br/>
eventArgs.Proceed();<br/>
return ;<br/>
} <br/>
catch <br/>
{<br/>
if (a == Count) throw ;<br/>
}<br/>
}<br/>
}<br/>
}<br/>
Using this attribute allows you to moderate the "whims" of the system. Also, its modified form can passively call the same function over and over again, aggregating the results of all calls. In my practice, this approach was useful, for example, when enumerating working SQL servers in a local network, because the first call to the search function certainly finds some servers, but alas, not all.[Serializable]<br/>
public class ExceptionDialogAttribute : OnExceptionAspect<br/>
{<br/>
public override void OnException(MethodExecutionEventArgs eventArgs)<br/>
{<br/>
ExceptionMessageBox emb = new ExceptionMessageBox(<br/>
eventArgs.Exception,<br/>
ExceptionMessageBoxButtons.OK,<br/>
ExceptionMessageBoxSymbol.Error);<br/>
emb.Show(eventArgs.Instance as Form);<br/>
eventArgs.FlowBehavior = FlowBehavior.Continue;<br/>
}<br/>
}<br/>
Unlike the usual MessageBox
I used the more beautiful and useful ExceptionMessageBox
. The idea, in principle, is quite simple. And of course this aspect can be customized to ignore exceptions of a particular type altogether. For example, when initializing add-ins in Visual Studio, an exception of type ArgumentException
is a common thing, since the studio sometimes tries to add menu items for commands that already exist. To “swallow” an exception, you can use the following aspect:[Serializable]<br/>
public class IgnoreExceptionAttribute : OnExceptionAspect<br/>
{<br/>
private Type type;<br/>
public IgnoreExceptionAttribute(Type type)<br/>
{<br/>
this .type = type;<br/>
}<br/>
public override Type GetExceptionType(System.Reflection.MethodBase method)<br/>
{<br/>
return type;<br/>
}<br/>
public override void OnException(MethodExecutionEventArgs eventArgs)<br/>
{<br/>
eventArgs.FlowBehavior = FlowBehavior.Continue;<br/>
} <br/>
}<br/>
When creating websites on ASP.NET, I have a slightly different approach - I issue a “safe” page when an exception occurs, but I want the process of throwing out an exception (which, in fact, ASP.NET MVC system processes), it was intercepted and logged. For this, I use the CodePlex.Diagnostics framework and this simple aspect:[Serializable]<br/>
public sealed class InterceptExceptionAttribute : OnExceptionAspect<br/>
{<br/>
public override void OnException(MethodExecutionEventArgs eventArgs)<br/>
{<br/>
IIdentity identity = WindowsIdentity.GetCurrent();<br/>
Guid guid = ExceptionProvider.Publish(eventArgs.Exception, identity);<br/>
throw new PublishedException(guid, eventArgs.Exception);<br/>
}<br/>
}<br/>
Debug.WriteLine
:[Serializable]<br/>
public sealed class LogAttribute : OnMethodBoundaryAspect<br/>
{<br/>
private static int indent;<br/>
private static int indentSize = 4;<br/>
private static string IndentString<br/>
{<br/>
get<br/>
{<br/>
return new string (Enumerable.Range(0, indentSize*indent).Select(n => n%4 == 0 ? '|' : ' ' ).ToArray());<br/>
}<br/>
}<br/>
private static void Indent() { ++indent; }<br/>
private static void Unindent() { if (indent > 0) --indent; }<br/>
private static void WriteLine( string s) { Debug.WriteLine(IndentString + s); }<br/>
public override void OnEntry(MethodExecutionEventArgs eventArgs)<br/>
{<br/>
StringBuilder sb = new StringBuilder();<br/>
sb.AppendFormat( "Entering {0} with arguments" , eventArgs.Method);<br/>
object [] args = eventArgs.GetReadOnlyArgumentArray() ?? new object [] {};<br/>
foreach (var arg in args)<br/>
{<br/>
sb.AppendFormat( " <{0}>" , arg);<br/>
}<br/>
WriteLine(sb.ToString());<br/>
Indent();<br/>
}<br/>
public override void OnExit(MethodExecutionEventArgs eventArgs)<br/>
{<br/>
Unindent();<br/>
WriteLine( "Exiting " + eventArgs.Method);<br/>
}<br/>
public override void OnException(MethodExecutionEventArgs eventArgs)<br/>
{<br/>
StringBuilder sb = new StringBuilder();<br/>
sb.AppendFormat( "Exception {0} in {1}" , eventArgs.Exception, eventArgs.Method);<br/>
sb.AppendLine();<br/>
WriteLine(sb.ToString());<br/>
}<br/>
}<br/>
It should be mentioned here that for logging there is the addition of Log4PostSharp , which records information on the input and output of methods using the subsystem log4net .[Serializable]<br/>
public class PerformanceCounterAttribute : OnMethodInvocationAspect<br/>
{<br/>
private static readonly Dictionary< string , PerformanceCounterAttribute><br/>
attributes = new Dictionary< string , PerformanceCounterAttribute>();<br/>
private long elapsedTicks;<br/>
private long hits;<br/>
[NonSerialized]<br/>
private MethodBase method;<br/>
public MethodBase Method { get { return method; } }<br/>
public double ElapsedMilliseconds<br/>
{<br/>
get { return elapsedTicks / (Stopwatch.Frequency / 1000d); }<br/>
}<br/>
public long Hits { get { return hits; } }<br/>
public static IDictionary< string , PerformanceCounterAttribute> Attributes<br/>
{<br/>
get<br/>
{<br/>
return attributes;<br/>
}<br/>
}<br/>
public override void OnInvocation(MethodInvocationEventArgs eventArgs)<br/>
{<br/>
Stopwatch stopwatch = Stopwatch.StartNew();<br/>
try <br/>
{<br/>
eventArgs.Proceed();<br/>
}<br/>
finally <br/>
{<br/>
stopwatch.Stop();<br/>
Interlocked.Add( ref elapsedTicks, stopwatch.ElapsedTicks);<br/>
Interlocked.Increment( ref hits);<br/>
}<br/>
}<br/>
public override void RuntimeInitialize(MethodBase method)<br/>
{<br/>
base .RuntimeInitialize(method);<br/>
this .method = method;<br/>
attributes.Add(method.Name, this );<br/>
}<br/>
}<br/>
Such an interesting PostSharp. And what aspects do you know?Source: https://habr.com/ru/post/62232/
All Articles