Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implement method decorators in C#

In python is possible to implement function decorators to extend the behavior of functions and methods.

In particular I'm migrating a device lib from python to C#. The communication with device can generate errors which should reraised with custom exception.

In python I would write like this:

@device_error_wrapper("Device A", "Error while setting output voltage.")   
def set_voltage(self, voltage):
    """
    Safely set the output voltage of device.
    """
    self.__handle.write(":source:voltage:level {0}".format(voltage))

This method call would expand to

try:
    self.__handle.write(":source:voltage:level {0}".format(voltage))
except Error:
    raise DeviceError("Error while setting output voltage.", "DeviceA")

With this pattern you can easily wrap and extend methods without having to write every try-except clause in every method.

Is it to possible to implement a similar pattern using C#?

If the implementation of the decorator (device_error_wrapper) is needed, please tell.

like image 992
Razer Avatar asked Mar 10 '13 13:03

Razer


2 Answers

As others have pointed out, tools like PostSharp allow you to weave in the cross cutting logic during (actually, after) compilation.

The alternative is to do it in runtime. Some IoC tools allow you to define the interceptors which are then added to proxy classes to your implementation. This sounds much more complex then it really is, so I will show an example based on Castle DynamicProxy.

First you define your class which needs to be wrapped.

[Interceptor(typeof(SecurityInterceptor))]
public class OrderManagementService : IOrderManagementService
{
    [RequiredPermission(Permissions.CanCreateOrder)]
    public virtual Guid CreateOrder(string orderCode)
    {   
        Order order = new Order(orderCode);
        order.Save(order); // ActiveRecord-like implementation
        return order.Id;
    }
} 

RequiredPermission serves as a decorator here. The class itself is adorned with Interceptor attribute specifying the handler for the interface method calls. This can also be put into configuration, so it is hidden from the class.

The interceptor implementation contains the decorator logic

class SecurityInterceptor : IMethodInterceptor
{
    public object Intercept(IMethodInvocation invocation, params object[] args)
    {
        MethodInfo method = invocation.Method;
        if (method.IsDefined(typeof(RequiredPermission), true) // method has RequiredPermission attribute
            && GetRequiredPermission(method) != Context.Caller.Permission) {
            throw new SecurityException("No permission!");  
        }

        return invocation.Proceed(args);
    }

    private Permission GetRequiredPermission(MethodInfo method)
    {
         RequiredPermission attribute = (RequiredPermission)method.GetCustomAttributes(typeof(RequiredPermission), false)[0];
        return attribute.Permission;
    }
} 

There are some drawbacks, however:

  • with DynamicProxy you can only wrap interfaces and virtual methods.
  • you need to instantiate the object via IoC container and not directly (which is not a problem if you already use IoC container)
like image 100
Zdeslav Vojkovic Avatar answered Oct 15 '22 21:10

Zdeslav Vojkovic


You can achieve something similar using Aspect Oriented Programming. I've only used PostSharp in the past but it's not free for commercial use though.

There are other AOP solutions out there and you can certainly achieve something similar using Mono.Cecil, but it would require more work.

Reza Ahmadi wrote a nice little introduction article called Aspect Oriented Programming Using C# and PostSharp. It can give you a clear enough idea of what to expect and how it works.

like image 43
Jensen Avatar answered Oct 15 '22 21:10

Jensen