Christian Smolka
Christian Smolka

Reputation: 159

Passing a random method as a parameter?

Is there any way in C# to pass a random method as a parameter?

To explain my question:

I want to write a simple Logger-Tool that reports the entering and leaving of a method with the passed arguments an the class and method name:

The log file I'm aiming at:

ENTERING: ClassOfDoom::MethodOfDoom( arg1={1} [int], arg2={true} [bool] )
LEAVING: ClassOfDoom::MethodOfDoom RETURNING 1 [int]

The code I have in mind:

class ClassOfDoom {
  // Remeber: MethodOfDoom is a _random_ method with _random_ arguments
  public int MethodOfDoom(int arg1, bool arg2) {
    Log.Entering(this, this.MethodOfDoom, arg1, arg2);
    ...
    return Log.Returing(this, this.MethodOfDoom, 1);
  }
}

Is there a way to achieve this? Or isn't C# as flexible as that?

Thanks in advance!

Upvotes: 2

Views: 1746

Answers (5)

user139444
user139444

Reputation:

I have used PostSharp to do this very thing before.

Upvotes: 0

Marc Gravell
Marc Gravell

Reputation: 1062935

You could do it with Expression easily enough - it would look something like:

Log.Capture(() => this.MethodOfDoom(arg1, arg2));

Here's an example; I've been a bit lazy using Compile().DynamicInvoke() to read the arg-values - for real code I'd try to read it more directly:

using System;
using System.Diagnostics;
using System.Linq.Expressions;
class Program
{
    DateTime MethodOfDoom(string s, int i)
    {
        return DateTime.Today;
    }
    public void RunTest()
    {
        int i =123;
        Log.Capture(() => this.MethodOfDoom("abc", i));
    }
    static void Main()
    {
        new Program().RunTest();
    }
}
static class Log
{
    public static T Capture<T>(Expression<Func<T>> method)
    {   
        MethodCallExpression mce = method.Body as MethodCallExpression;
        if (mce == null) throw new InvalidOperationException(
             "Method-call expected");
        string name = mce.Method.Name;
        try
        {
            int i = 0;
            foreach(var param in mce.Method.GetParameters())
            {
                object argValue = Expression.Lambda(mce.Arguments[i++])
                        .Compile().DynamicInvoke();
                Trace.WriteLine(param.Name + "=" + argValue, name);
            }
            Trace.WriteLine("ENTERING", name);
            T result = method.Compile().Invoke();
            Trace.WriteLine("EXITING: " + result, name);
            return result;
        }
        catch (Exception ex)
        {
            Trace.WriteLine("EXCEPTION: " + ex, name);
            throw;
        }
    }
}

Upvotes: 3

Chris Melinn
Chris Melinn

Reputation: 2076

If widely used in your code, this scenario is best implemented using Aspect Oriented Programming (AOP) techniques. There are different frameworks that can be used (such as Spring.NET AOP), which you can use in your .NET application. Here is a reference article that might help you get started:

http://www.developer.com/lang/article.php/10924_3795031_2

The referenced article gives you the logging enter/exit scenario as an example.

Upvotes: 2

Mehrdad Afshari
Mehrdad Afshari

Reputation: 422026

You can make your logging function take a MethodBase argument and use MethodBase.GetCurrentMethod to pass the current method info as an argument.

Then, in the logger, you could check its properties Name and DeclaringType to get the method information. Also, passing parameters is easy by declaring a params object[] args parameter in the logging function:

public static void Entering(object obj, MethodBase methodInfo,
                            params object[] args) {
    Console.WriteLine("ENTERING {0}:{1}", methodInfo.DeclaringType.Name,
                                          methodInfo.Name);
    ...
}

Upvotes: 5

LorenzCK
LorenzCK

Reputation: 7471

I'm not sure I entirely understand your question, but if you are trying to make a call to Log.Entering and Log.Returning inside an arbitrary (random) method and using the method's actual parameters, you should check out PostSharp. It will allow you to inject code in a method body and then do some work based on the reflected method information you get from the .NET framework (and the actual parameters passed to the method at runtime).

Upvotes: 3

Related Questions