Skip to content

Repository files navigation

MethodDecorator.Fody

Build statusNuGet Status

Compile time decorator pattern via IL rewriting.

See Milestones for release notes.

This is an add-in for Fody

It is expected that all developers using Fody become a Patron on OpenCollective. See Licensing/Patron FAQ for more information.

Usage

See also Fody usage.

NuGet installation

Install the MethodDecorator.Fody NuGet package and update the Fody NuGet package:

PM>Install-Package Fody
PM>Install-Package MethodDecorator.Fody

The Install-Package Fody is required since NuGet always defaults to the oldest, and most buggy, version of any dependency.

Your Code

// Attribute should be "registered" by adding as module or assembly custom attribute[module:Interceptor]// Any attribute which provides OnEntry/OnExit/OnException with proper args[AttributeUsage(AttributeTargets.Method|AttributeTargets.Constructor|AttributeTargets.Assembly|AttributeTargets.Module)]publicclassInterceptorAttribute:Attribute,IMethodDecorator{// instance, method and args can be captured here and stored in attribute instance fields// for future usage in OnEntry/OnExit/OnExceptionpublicvoidInit(objectinstance,MethodBasemethod,object[]args){TestMessages.Record(string.Format("Init: {0} [{1}]",method.DeclaringType.FullName+"."+method.Name,args.Length));}publicvoidOnEntry(){TestMessages.Record("OnEntry");}publicvoidOnExit(){TestMessages.Record("OnExit");}publicvoidOnException(Exceptionexception){TestMessages.Record(string.Format("OnException: {0}: {1}",exception.GetType(),exception.Message));}}publicclassSample{[Interceptor]publicvoidMethod(){Debug.WriteLine("Your Code");}}

What gets compiled

publicclassSample{publicvoidMethod(intvalue){InterceptorAttributeattribute=(InterceptorAttribute)Activator.CreateInstance(typeof(InterceptorAttribute));// in c# __methodref and __typeref don't exist, but you can create such ILMethodBasemethod=MethodBase.GetMethodFromHandle(__methodref(Sample.Method),__typeref(Sample));object[]args=newobject[1]{(object)value};attribute.Init((object)this,method,args);attribute.OnEntry();try{Debug.WriteLine("Your Code");attribute.OnExit();}catch(Exceptionexception){attribute.OnException(exception);throw;}}}

NOTE:this is replaced by null when the decorated method is static or a constructor.

IntersectMethodsMarkedByAttribute

This is supposed to be used as

// all MSTest methods will be intersected by the code from IntersectMethodsMarkedBy[module:IntersectMethodsMarkedBy(typeof(TestMethod))]

You can pass as many marker attributes to IntersectMethodsMarkedBy as you want

[module:IntersectMethodsMarkedBy(typeof(TestMethod),typeof(Fact),typeof(Obsolete))]

Example of IntersectMethodsMarkedByAttribute implementation

[AttributeUsage(AttributeTargets.Module|AttributeTargets.Assembly)]publicclassIntersectMethodsMarkedByAttribute:Attribute{// RequiredpublicIntersectMethodsMarkedByAttribute(){}publicIntersectMethodsMarkedByAttribute(paramsType[]types){if(types.All(x =>typeof(Attribute).IsAssignableFrom(x))){thrownewException("Meaningfull configuration exception");}}publicvoidInit(objectinstance,MethodBasemethod,object[]args){}publicvoidOnEntry(){}publicvoidOnExit(){}publicvoidOnException(Exceptionexception){}// Optional//public void OnTaskContinuation(Task task) {}}

Now all your code marked by [TestMethodAttribute] will be intersected by IntersectMethodsMarkedByAttribute methods. You can have multiple IntersectMethodsMarkedByAttributes applied if you want (don't have idea why). MethodDecorator searches IntersectMethodsMarkedByAttribute by predicate StartsWith("IntersectMethodsMarkedByAttribute")

In case of exception in async method you "OnException" will not be called, OnTaskContinuation will be called instead.

Icon

Icon courtesy of The Noun Project

About

Compile time decorator pattern via IL rewriting

Resources

Security policy

Stars

404 stars

Watchers

8 watching

Forks

Sponsor this project

Used by

Contributors

Languages