26

Is it possible to do that in C# 3 or 4? Maybe with some reflection?

class Magic
{

    [RunBeforeAll]
    public void BaseMethod()
    {
    }

    //runs BaseMethod before being executed
    public void Method1()
    {
    }

    //runs BaseMethod before being executed
    public void Method2()
    {
    }
}

EDIT

There is an alternate solution for this, make Magic a singleton and put your code on the getter of the static instance. That's what I did:

public class Magic
{

    private static Magic magic = new Magic();
    public static Magic Instance
    {
        get
        {
            magic.BaseMethod();
            return magic;
        }
    }

    public void BaseMethod()
    {
    }

    //runs BaseMethod before being executed
    public void Method1()
    {
    }

    //runs BaseMethod before being executed
    public void Method2()
    {
    }
}
CDspace
  • 2,639
  • 18
  • 30
  • 36
WoF_Angel
  • 2,569
  • 9
  • 35
  • 54
  • 4
    How about a constructor? – JConstantine Feb 08 '12 at 11:51
  • 2
    Using a constructor is no solution, because if i were to execute, say, two methods of one instance, i'd only get the basemethod to run once. Also very unfitting for static instances. – WoF_Angel Feb 08 '12 at 12:42
  • You could do this by using `dynamic` and implementing [`IDynamicMetaObjectProvider`](http://msdn.microsoft.com/en-us/library/system.dynamic.idynamicmetaobjectprovider.aspx). This will allow you to run your own code during binding, which happens before a method is executed. Note: This suggestion is provided as a curiosity. It's not actually a good way to solve your problem. – Brian Feb 08 '12 at 14:51

9 Answers9

14

You can't do this automatically in C# - you should probably be looking at AOP, e.g. with PostSharp.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I've some doubts about AOP as a solution for this, because I believe OP wants to execute a method before one method invocation and later don't "use" aspect anymore. Maybe some class instance flag like _Initialized_ and if it's _true_, do nothing in the aspect? – Matías Fidemraizer Feb 08 '12 at 12:15
  • @MatíasFidemraizer: I don't believe so, based on a later comment: "Using a constructor is no solution, because if i were to execute, say, two methods of one instance, i'd only get the basemethod to run once" - so I believe the OP wants the method to be run on *every* invocation. – Jon Skeet Feb 08 '12 at 13:39
  • Well, then, PostSharp (or any other AOP framework) is our solution! This comment was published after my doubts. And, I believe this is the right answer, because _IL weaving_ is better than proxying for this case. – Matías Fidemraizer Feb 08 '12 at 14:25
13

There is an alternate solution for this, make Magic a singleton and put your code on the getter of the static instance. That's what i did.

public class Magic{

private static Magic magic;
public static Magic Instance{
  get
    {
   BaseMethod();
    return magic;
    }
}

public void BaseMethod(){
}

//runs BaseMethod before being executed
public void Method1(){
}

//runs BaseMethod before being executed
public void Method2(){
}
}
WoF_Angel
  • 2,569
  • 9
  • 35
  • 54
  • 1
    this looks interesting but it will not work. private field is not initiated. If you explain how to initiate magic field, this may work. – hakan Aug 06 '13 at 15:13
  • 2
    You could do a lazy init, i.e checking if null before accesing (usually only first time). If it is, instanciate it. – CBinet Dec 09 '17 at 20:05
  • 1
    Interesting to see how this can not work https://stackoverflow.com/a/40242336/3873799 – alelom Nov 10 '21 at 13:32
4

I know it won't answer the question directly. But it's a good approach to use a decorator pattern to solve this problem to make your implementation stay clean.

Create an interface

public interface IMagic
{


    public void Method1()
    {
    }


    public void Method2()
    {
    }
}

Create implementation

public class Magic : IMagic
{

    public void Method1()
    {
    }


    public void Method2()
    {
    }
}

Create Decorator

public class MagicDecorator : IMagic
{
   private IMagic _magic;
   public MagicDecorator(IMagic magic)
   {
       _magic = magic;
   }

   private void BaseMethod()
   {
       // do something important
   }

    public void Method1()
    {
         BaseMethod();
         _magic.Method1();
    }


    public void Method2()
    {
        BaseMethod();
        _magic.Method2();
    }
}

Usage

var magic = new MagicDecorator(new Magic());
magic.Method1();
magic.Method2();
Anang Satria
  • 1,226
  • 1
  • 15
  • 19
  • 3
    Even with the decorator, one still needs to call the BaseMethod from within it - I suspect OP wants the basemethod to be called automatically. – BenKoshy May 05 '19 at 12:38
3

What you want can be done with AOP - some links to .NET C# AOP frameworks:

Yahia
  • 69,653
  • 9
  • 115
  • 144
2

If you use a dependency injection framework, to generate the instance, then you can use interceptors for method calls.

public class CallLogger : IInterceptor
{
    TextWriter _output;

    public CallLogger(TextWriter output)
    {
        _output = output;
    }

    public void Intercept(IInvocation invocation)
    {
        _output.Write("Calling method {0} with parameters {1}... ",
        invocation.Method.Name,
        string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray()));

        invocation.Proceed();

        _output.WriteLine("Done: result was {0}.", invocation.ReturnValue);
    }
}

You can check autofac's documentation and sample for more info. https://autofaccn.readthedocs.io/en/latest/advanced/interceptors.html

Serdar
  • 1,416
  • 2
  • 17
  • 43
1

Just to make a thing clear why the following implementation won't work:

public class Magic{

private static Magic magic = new Magic();
public static Magic Instance{
  get
    {
   magic.BaseMethod();
    return magic;
    }
}

public void BaseMethod(){
}

//runs BaseMethod before being executed
public void Method1(){
}

//runs BaseMethod before being executed
public void Method2(){
}
}

in the case you just want to hold a Magic object, the method will be randomly called:

Magic m = Magic.Instance; //this will trigger unwanted call on BaseMethod

and also if one will want to call the BaseMethod, it will be called twice:

Magic.Instance.BaseMethod(); //two calls of the BaseMethod

which of course have a workaround, to return unwanted objects using get:

var unused = Magic.Instance;

Only to summarize: This is not possible (at least yet) in C#.

meJustAndrew
  • 6,011
  • 8
  • 50
  • 76
1

Yes, you can! with a static constructor, it will run once before the class is referenced and you can do what you like in it.

Like this:

public class Magic{

static Magic()
{
    BaseMethod();
}

public void BaseMethod(){
}

//runs BaseMethod before being executed
public void Method1(){
}

//runs BaseMethod before being executed
public void Method2(){
}
}

Here's the Microsoft doc:

https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-constructors

Liron Achdut
  • 881
  • 10
  • 12
1

Use https://github.com/Fody/Fody . The licencing model is based on voluntary contributions making it the better option to PostSharp which is a bit expensive for my taste.

[module: Interceptor]
namespace GenericLogging
{

[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)
        {
            Console.WriteLine(string.Format("Init: {0} [{1}]", method.DeclaringType.FullName + "." + method.Name, args.Length));
        }

        public void OnEntry()
        {
            Console.WriteLine("OnEntry");
        }

        public void OnExit()
        {
            Console.WriteLine("OnExit");
        }

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

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

[TestMethod]
public void TestMethod2()
{
    Sample t = new Sample();
    t.Method(1);
}
Nigel Findlater
  • 1,684
  • 14
  • 34
-1

I've recently had cause to do this. I'll spare you the probably boring details of my use-case, except to state that I want the method DoThisFirst to run before the specific method I'm calling. Still learning C# so probably not the best way to do it...

using System;

namespace ConsoleApp1
{
    class Class1
    {
        public enum MethodToCall
        {
            Method2,
            Method3
        }

        public delegate void MyDelegate(int number = 0, bool doThis = false, double longitude = 32.11);

        public static void DoThisFirst(int number, bool doThis, double longitude)
        {
            Console.WriteLine("DoThisFirst has been called.");
        }

        public static void DoSomethingElse(int number, bool doThis, double longitude)
        {
            Console.WriteLine("DoSomethingElse has been called.");
        }

        public static void DoAnotherThing(int number, bool doThis, double longitude)
        {
            Console.WriteLine("DoAnotherThing has been called.");
        }

        public static void Main()
        {
            void Action(MethodToCall methodToCall)
            {
                MyDelegate myDel;

                myDel = new MyDelegate(DoThisFirst);

                switch (methodToCall)
                {
                    case MethodToCall.Method2:
                        myDel += DoSomethingElse;
                        break;
                    case MethodToCall.Method3:
                        myDel += DoAnotherThing;
                        break;
                }

                myDel.Invoke();
            }

            Action(MethodToCall.Method3);

            Console.ReadKey();
        }
    }
}
Zuno
  • 433
  • 1
  • 7
  • 17