Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在C中实现方法修饰符#_C#_Python_Design Patterns_Decorator - Fatal编程技术网

C# 在C中实现方法修饰符#

C# 在C中实现方法修饰符#,c#,python,design-patterns,decorator,C#,Python,Design Patterns,Decorator,在python中,可以实现function decorators来扩展函数和方法的行为 特别是,我正在将设备库从python迁移到C。与设备的通信可能会产生错误,这些错误应通过自定义异常重新确认 在python中,我会这样写: @device_error_wrapper("Device A", "Error while setting output voltage.") def set_voltage(self, voltage): """ Safely set the o

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

特别是,我正在将设备库从
python
迁移到
C
。与设备的通信可能会产生错误,这些错误应通过自定义异常重新确认

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
实现类似的模式


如果需要decorator(
device\u error\u wrapper
)的实现,请告知。

您可以使用。我只在过去使用过,但它不是免费的商业用途

还有其他AOP解决方案,您当然可以使用它实现类似的功能,但这需要更多的工作


雷扎·艾哈迈迪写了一篇很好的介绍文章,名为。它可以让您清楚地了解所期望的内容以及它是如何工作的。

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


我也看到过通过装饰类实际包装类来实现这一点,但这需要大量的工作,我不认为这可以用一种真正通用的方式来完成。维基百科在

中显示了这一点,正如其他人提到的,您正在寻找AOP。PostSharp是一个很好的编译后解决方案,但它是一个运行时AOP解决方案。

正如其他人所指出的,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
在这里充当装饰者。类本身用
拦截器
属性修饰,该属性指定接口方法调用的处理程序。这也可以放入配置中,因此它对类是隐藏的

拦截器实现包含decorator逻辑

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容器,这不是问题)

我知道的另一种选择是使用代理(本答案中的示例),或者您可以尝试postsharp(在其中一个答案中也提到)。如果真的可以将属性用作方法装饰器,我不知道(我对此表示怀疑,但我打赌有人会为您解答这个问题)。与Mono.Cecil相关。你可以看看西蒙·克洛普的福迪。这是一个很好的小插件,可以帮助您将预构建的方面编织到代码中。它还包含一个模板来帮助您构建自己的方面。