0

suppose I have this class:

Class Foo:
        method1(){}
        method2(){}
        method3(){}
...

And suppose I have some action I wanted to do repeatedly in several methods in the class. Each action will take before the methods occur and after it occur. Is there an elegant way to implement it? The only way came to my mind:

private void Setup(Action action)
{
  //Do something before
  action
  //Do something after
}

private void method1(args)
{
   Setup(()=>method)
}

But it will make me call repeatedly call for Setup in each function I would like to implement it.

  • 2
    Explain what you want to do. If you want to implement aspects, there are a *lot* of techniques and mechanisms available. ASP.NET MVC and Core do it through middleware in a request pipeline for example. At a smaller scale, you can use functional-style techinques like currying or wrapping one `Func<>` inside another to create functions that do whatever you want before calling the innermost function – Panagiotis Kanavos Dec 10 '19 at 13:37
  • Does this answer your question? [Simple Delegate (delegate) vs. Multicast delegates](https://stackoverflow.com/questions/2192219/simple-delegate-delegate-vs-multicast-delegates) – panoskarajohn Dec 10 '19 at 13:37
  • 1
    This sort of stuff is typically handled through an IL rewriter like PostSharp, or else through the use of proxies (Castle and related libraries). Some hand-rolled reflection is also feasible for simple scenarios (`Type.GetMethods()`), possibly combined with T4 code generation. – Jeroen Mostert Dec 10 '19 at 13:37
  • To me it sounds like you are describing a multicast delegate. – panoskarajohn Dec 10 '19 at 13:38
  • ASP.NET MVC/Core don't use reflection though. They're engineered in a way that allows injecting middleware. The result is far faster than using reflection. Functional programming doesn't need IL either, but again, it requires writing code in a specific way. – Panagiotis Kanavos Dec 10 '19 at 13:39
  • 1
    @panoskarajohn a multicast delegate does something very specific and very different than what the OP asked. The OP wants to run custom code before and after a call. A multicast delegate does something very different - it calls mulitple delegates when triggered – Panagiotis Kanavos Dec 10 '19 at 13:40
  • 1
    For me, elegance is in simplicity. So consider your requirements (with half an eye on scalability / future direction). And implement DRY by KISS – ne1410s Dec 10 '19 at 13:42
  • Other techniques - Channels (my current obsession). You can compose methods that accept a ChannelReader as input and produce a ChannelReader with (possibly) modified data as output and compose them, so that the final result will pass through multiple "transforms" before it reaches the target. That's more for pipeline processing though – Panagiotis Kanavos Dec 10 '19 at 13:42
  • 3
    @ne1410s that's why AOP techniques were created. If you want a logged operation, why not create a "wrapper" that logs before or after the actual call? A lot simpler than sprinkling log calls everywhere. The same for timing, validation, etc. There's no single technique though. – Panagiotis Kanavos Dec 10 '19 at 13:43
  • AOP techniques is the best way to do this. You can implement [realproxy](https://learn.microsoft.com/en-us/archive/msdn-magazine/2014/february/aspect-oriented-programming-aspect-oriented-programming-with-the-realproxy-class) or use [dynamicproxy](http://www.castleproject.org/dynamicproxy/index.html). AOP is usefull to add logging. – Tohm Dec 10 '19 at 13:55

1 Answers1

1

I have made a quick exemple with DispatchProxy Inspiration : DispatchProxy

https://dotnetfiddle.net/GzDR9r

using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;

//https://www.c-sharpcorner.com/article/aspect-oriented-programming-in-c-sharp-using-dispatchproxy/
public class Program
{

    public static void Main()
    {
        var foo = new  Foo();
        var decoratedFoo = AspectDecorator<IFoo>.Create(foo);

        Console.WriteLine("\n\nClass:\n");
        foo.method1();
        foo.method2();
        foo.method3();

        Console.WriteLine("\n\nDecorated Class:\n");
        decoratedFoo.method1();
        decoratedFoo.method2();
        decoratedFoo.method3();


    }

}
public class Foo : IFoo{
        public void method1(){Console.WriteLine("> call method1");}
        public void method2(){Console.WriteLine("> call method2");}
        public void method3(){Console.WriteLine("> call method3");}
}
public interface IFoo{
    void method1();
    void method2();
    void method3(); 
}
public class AspectDecorator<T> : DispatchProxy 
{
    private T _impl;
    protected override object Invoke(MethodInfo targetMethod, object[] args)
    {
        Console.WriteLine($"Before : {targetMethod.Name}");
        var obj =  _impl.GetType().GetMethod(targetMethod.Name).Invoke(_impl, args);
        Console.WriteLine($"After : {targetMethod.Name}");
        return obj;
    }
    public void SetTarget(T target)
    {
        this._impl = target;
    }
    public static T Create(T decorated)
    {
        object proxy = Create<T, AspectDecorator<T>>();
        ((AspectDecorator<T>) proxy)._impl=decorated;
        return (T)proxy;
    }


}
Tohm
  • 305
  • 1
  • 5