Git Product home page Git Product logo

methoddecorator's Introduction

Icon

The nuget package NuGet Status

https://nuget.org/packages/MethodDecorator.Fody/

PM> Install-Package MethodDecorator.Fody

This is an add-in for Fody

Compile time decorator pattern via IL rewriting

Introduction to Fody

This version is fork of Fody/MethodDecorator with changes I found useful

Differences from original Fody/MethodDecorator:

  • No attributes or interfaces in root namespace (actually without namespace) are required
  • Interceptor attribute can be declared and implemented in a separate assembly
  • Init method is called before any method and receives the method reference and args
  • OnEntry/OnExit/OnException methods don't receive the method reference anymore
  • IntersectMethodsMarkedByAttribute attribute allows you to intersect a method marked by any attribute

Your Code

// Atribute 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)]
public class InterceptorAttribute : Attribute, IMethodDecorator	{
    // instance, method and args can be captured here and stored in attribute instance fields
	// for future usage in OnEntry/OnExit/OnException
	public void Init(object instance, MethodBase method, object[] args) {
		TestMessages.Record(string.Format("Init: {0} [{1}]", method.DeclaringType.FullName + "." + method.Name, args.Length));
	}
	public void OnEntry() {
        TestMessages.Record("OnEntry");
    }

    public void OnExit() {
        TestMessages.Record("OnExit");
    }

    public void OnException(Exception exception) {
        TestMessages.Record(string.Format("OnException: {0}: {1}", exception.GetType(), exception.Message));
    }
}

public class Sample	{
	[Interceptor]
	public void Method()
	{
	    Debug.WriteLine("Your Code");
	}
}

What's gets compiled

public class Sample {
	public void Method(int value) {
	    InterceptorAttribute attribute = 
	        (InterceptorAttribute) Activator.CreateInstance(typeof(InterceptorAttribute));
	    
		// in c# __methodref and __typeref don't exist, but you can create such IL 
		MethodBase method = MethodBase.GetMethodFromHandle(__methodref (Sample.Method), 
														   __typeref (Sample));
	    
		object[] args = new object[1] { (object) value };
		
		attribute.Init((object)this, method, args);

		attribute.OnEntry();
	    try {
	        Debug.WriteLine("Your Code");
	        attribute.OnExit();
	    }
	    catch (Exception exception) {
	        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)]
public class IntersectMethodsMarkedByAttribute : Attribute {
	// Required
	public IntersectMethodsMarkedByAttribute() {}

	public IntersectMethodsMarkedByAttribute(params Type[] types) {
		if (types.All(x => typeof(Attribute).IsAssignableFrom(x))) {
			throw new Exception("Meaningfull configuration exception");
		}
	}
	public void Init(object instance, MethodBase method, object[] args) {}
	public void OnEntry() {}
	public void OnExit() {}
	public void OnException(Exception exception) {}
}

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")

Planned

  • Make Init method optional
  • Add "this" as parameter to Init method if method is not static
  • Pass return value to "OnExit" if method returns any

Icon

Icon courtesy of The Noun Project

methoddecorator's People

Contributors

alex-y-su avatar simoncropp avatar citizenmatt avatar aiexandr avatar davidalpert avatar ursenzler avatar

Watchers

James Cloos avatar Orellabac avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.