Decorate method with custom attributes

12,186

Solution 1

There is no built in way to do this in .NET.

If your wish is not to use any 3rd party libraries (as you said in one of your comments), doing code weaving or dynamic proxy generation is a lot of work. In that case it's better to step away from using attributes and go with the decorator design pattern. Here's an example:

// Define an interface for the operation
public interface IMyLongRunningTask
{
    DBResult longTask(DBCommand command);
}

// Define an implementation for the operation:
public class MyLongRunningTask : IMyLongRunningTask
{
    public DBResult longTask(DBCommand command)
    {
        // code here
    }
}

And now you can write a decorator for the IMyLongRunningTask:

public class MyLongRunningTaskMonitor : IMyLongRunningTask
{
    private readonly IMyLongRunningTask wrappedService;
    private readonly ILogger logger;

    public MyLongRunningTaskMonitor(IMyLongRunningTask wrapped,
        ILogger logger)
    {
        this.wrappedService = wrapped;
        this.logger = logger;
    }

    public DBResult longTask(DBCommand command)
    {
        var watch = Stopwatch.CreateNew();

        var result = this.wrappedService.longTask(command);

        this.logger.Log("longTask executed in " + 
            watch.ElapsedMilliseconds + " ms.");

        return result;
    }
}

When you use dependency injection, you can easily configure an MyLongRunningTaskMonitor to be returned when an IMyLongRunningTask is requested. For instance:

container.Register<IMyLongRunningTask>(() =>
    new MyLongRunningTaskMonitor(
        container.GetInstance<MyLongRunningTask>(),
        container.GetInstance<ILogger>()
    )
);

Solution 2

You could use Castle DynamicProxy.

DynamicProxy generates proxies for your objects that you can use to transparently add or alter behavior to them, provide pre/post processing and many other things.

Share:
12,186
0xDEAD BEEF
Author by

0xDEAD BEEF

@ whiteCryption.

Updated on June 04, 2022

Comments

  • 0xDEAD BEEF
    0xDEAD BEEF almost 2 years

    I have some functions for which I want to log time consumed in them.

    DBResult LongTask(DBCommand command)
    {
       ...
    }
    

    Is there a way to attchieve this

    [LogTimeUsed()]
    DBResult LongTask(DBCommand command)
    {
       ...
    }
    

    So that I can have class/function somewhere which gets called every time when this function is called and I can inject my own code, get access to command and DBResult and log time spent in function?