ppittle / pMixins

pMixins - Mixin framework for C#
http://pMixins.com
Apache License 2.0
23 stars 5 forks source link

Wrap try/catch/log recipe #38

Closed dzmitry-lahoda closed 9 years ago

dzmitry-lahoda commented 9 years ago

Update docs to show how to do next if possible.

Given

class A{
int Foo(int a,int b)
{
   return a/b;
}
}

Generate

class B
{
  B(A a){
//..
} 
int Foo(int a,int b)
{
try
{
  return a.Foo(a,b)
}  
catch(Exceptions a)
  // wrapper actions
}
}

Wrapper actions

throw new MyException(ex);
Log.Write(ex);
return default(int);
var newEx = ExceptionPolicy.Wrap(ex);
if (newEx != null) throw newEx;
throw;
return base.Foo(a,b); // if A has base class with Foo and Foo is virtual

Defined how to work if A and B has same interface. Define if we have A1,A2,A3 to generated several B(is why at all need such generation). Defined some query to filter out some methods which should not be wrapped.

ppittle commented 9 years ago

Hi asd-and-Rizzo,

This can be done in the current version by creating a class that implements IMixinInterceptor and provides try/catch functionality in the OnAfterMethodInvocation method. Easiest way to do this is to inherit from MixinInterceptorBase:

public class TryCatchInterceptor : MixinInterceptorBase
{
     public override void OnAfterMethodInvocation(object sender, MethodEventArgs eventArgs)
     {
            if (null == eventArgs.MemberInvocationException)
                //Nothing to do, method did not throw exception
                return;

           //Log Error

           bool handleError = true;

            if (handleError)
            {
                eventArgs.CancellationToken = new CancellationToken();

                //if necessary set the value to be returned.
                eventArgs.ReturnValue = new object();
            }
            else
            {
                //Do nothing.  The exception will be thrown.
            }
     }
}

You can them use this Interceptor:

[pMixin(Target = typeof(WhateverYouWant),  Interceptors = new[] { typeof(TryCatchInterceptor)})]
public partial class Example{}

Note: This support will likely be deprecated in the future. Other tools (such as PostSharp) provide this functionality in a more robust and universal manner. Keeping support for Interceptors additionally complicates the pMixins code base and doesn't directly contribute to it's core goal of Composition.

dzmitry-lahoda commented 9 years ago

Thanks for clarification of core goal and sample. But several points I may add: 1."pMixins Code Generation Framework" implies support for case like I mentioned. I suggest to rename "pMixins Composition Code Generation Add-in for Visual Studio" if not.

Framework is on what you can build several applications/libraries/tools. .NET and ASP.NET vNEXT are frameworks. pMinixs not. What may be expected from code generation Framework?

On first layer NRefactory or Roslyn are added with simplest shortcuts to do things with code.

Second layer is object oriented procedural code to do code generation/manipulation and VALIDATION.

Third layer is view on this code: mocking library style DSL or composition oriented attribute based library.

Forth is application/tools: out of T4 or out of VS Add-in.

  1. PostSharp is closed source commercial app. Which precludes its usage on most of projects.
  2. Looks like current interceptors in pMixin use reflection to bundle arguments and return (and invoke?), but I thought that real value of working directly with code is in avoiding any reflection. Which is possible as I tested.
  3. Most of IL runtime generators are slow because of reflection proxy approach like in 3. And IL generation make app start slow (real use case on real project replaces IL emit runtime with NRefactory+T4 compile). And IL emit does not work on AOT(devices). So need code generation.
  4. I suggest to look here http://www.cs.rit.edu/~ear7631/aop/AOPWriteUpPDF.pdf. It does real AOP with almost not performance penalty. And seems AspectJ support both bytecode and Java code weaving(not sure about second). I yet to see such thing on .NET.
  5. If there is "performance" issue, and it is if reflection used, and pMixin uses it for other scenarios - then large scale Composition precluded.
  6. Decorator pattern based on delegation is Composition.
  7. Decoration may lifted off while working with code generation (which is of great value):
class B
{
int Foo(int a,int b)
{
try
{
  return a/b;//embed body direcly
}  
catch(Exceptions a)
  // wrapper actions
}
}