10

python可以实现function decorators扩展函数和方法的行为。

特别是我正在将设备库pythonC#. 与设备的通信可能会产生错误,应使用自定义异常重新引发。

python我会这样写:

@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))

此方法调用将扩展为

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

使用这种模式,您可以轻松地包装和扩展方法,而无需try-except在每个方法中编写每个子句。

是否可以使用 实现类似的模式C#

如果需要装饰器(device_error_wrapper)的实现,请告知。

4

4 回答 4

8

正如其他人指出的那样,PostSharp 之类的工具允许您在编译期间(实际上是之后)编织横切逻辑。

另一种方法是在运行时进行。一些 IoC 工具允许您定义拦截器,然后将这些拦截器添加到您的实现的代理类中。这听起来比实际复杂得多,所以我将展示一个基于 Castle DynamicProxy 的示例。

首先,您定义需要包装的类。

[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在这里充当装饰者。类本身装饰有Interceptor指定接口方法调用的处理程序的属性。这也可以放入配置中,因此对类隐藏。

拦截器实现包含装饰器逻辑

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;
    }
} 

但是也有一些缺点:

  • 使用 DynamicProxy 你只能包装接口和虚拟方法。
  • 您需要通过 IoC 容器而不是直接实例化对象(如果您已经使用 IoC 容器,这不是问题)
于 2013-03-11T16:35:12.733 回答
5

您可以使用Aspect Oriented Programming实现类似的目标。我过去只使用过PostSharp,但它不是免费用于商业用途的。

还有其他 AOP 解决方案,您当然可以使用Mono.Cecil实现类似的目标,但这需要更多的工作。

Reza Ahmadi 写了一篇不错的小介绍文章,名为“使用 C# 和 PostSharp 进行面向方面编程” 。它可以让您清楚地了解预期的内容及其工作原理。

于 2013-03-10T14:09:09.140 回答
2

在 C# 中实现这样的装饰器没有简单的方法 - 默认情况下,自定义属性只是描述性的。然而,有些项目扩展了 C# 编译器或运行时,以便您可以实际使用它。我认为最好的是PostSharp。有了它,您可以定义这样的方法装饰器(通常是“方面”),并且该方法会在编译期间按照您的需要进行包装。

我也看到通过装饰器类实际包装你的类来实现这一点,但这是很多工作,我认为它不能以一种非常通用的方式完成。维基百科在装饰器模式文章中显示了这一点

于 2013-03-10T14:09:51.093 回答
1

正如其他人提到的那样,您正在寻找 AOP。PostSharp 是一个很好的后编译解决方案,但Castle DynamicProxy是一个运行时 AOP 解决方案。

于 2013-03-10T14:37:01.783 回答