Reputation: 8211
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.
Upvotes: 10
Views: 6188
Reputation: 14591
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:
Upvotes: 8
Reputation: 21255
As others have mentioned you are looking for AOP. PostSharp is a good post compile solution, but Castle DynamicProxy is a runtime AOP solution.
Upvotes: 1
Reputation: 10957
There's no easy way to implement such decorators in C# - custom Attributes are by default only descriptive. There are however projects that extend C# compiler or runtime so that you can actually use this. I think the best one is PostSharp. With it you can define such method decorator ("aspect" in general) and the method gets wrapped during compilation like you need.
I've also seen this implemented by actually wrapping your classes by decorator classes, but that's a lot of work and I don't think it can be done in a really general way. Wikipedia shows this in Decorator Pattern article
Upvotes: 2
Reputation: 3538
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.
Upvotes: 5