Реализовать способ декораторов в C#
на python
можно использовать function decorators
для расширения поведения функций и методов.
в частности, я переношу lib устройства из python
to C#
. Сообщение с прибором может произвести ошибки которые должны reraised с изготовленным на заказ исключением.
на 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 ответов
вы можете достичь чего-то подобного, используя Аспектно-Ориентированное Программирование. Я только использовал PostSharp в прошлом, но это не для коммерческого использования бесплатно.
есть и другие решения AOP, и вы, безусловно, можете достичь чего-то подобного, используя Mono.Сесил!--2-->, но это потребует больше работы.
Реза Ахмади написал небольшую вводную статью под названием аспектно-ориентированное программирование с использованием C# и PostSharp. Он может дать вам достаточно ясное представление о том, чего ожидать и как это работает.
как указывали другие, такие инструменты, как PostSharp, позволяют вам переплетать логику кросс-резки во время (на самом деле, после) компиляции.
альтернатива-сделать это в runtime. Некоторые инструменты 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)
нет легко способ реализации таких декораторов в C# -настраиваемые атрибуты по умолчанию только описательным. Однако есть проекты, которые расширяют компилятор или среду выполнения C#, чтобы вы могли фактически использовать это. Я думаю, что лучший из них PostSharp. С его помощью вы можете определить такой декоратор метода ("аспект" в целом), и метод будет обернут во время компиляции, как вам нужно.
Я также видел это реализовано путем фактической упаковки ваших классов классами декоратора, но это много работы, и я не думаю, что это можно сделать действительно общим способом. Википедия показывает это в статьи шаблон "декоратор"
Как уже упоминали другие, вы ищете AOP. PostSharp-хорошее решение для компиляции сообщений, но Замок DynamicProxy является решением AOP во время выполнения.