Как автоматически генерировать шаблон Decorator в C#

У меня есть некоторый интерфейс и класс, реализующий этот интерфейс, скажем:

interface IMyInterface
{
     void Func1();
     void Func2();
}

class Concrete : IMyInterface
{
     public virtual void Func1() { //do something }
     public virtual void Func2() { //do something }
}

Теперь я хочу создать класс, который украшает каждый из методов конкретного класса определенной логикой, которая будет выполняться в непроизводственной среде до и после вызова.

class Decorator : Concrete
{ 
     public override void Func1() { Pre(); base.Func1; Post(); }
     public override void Func2() { Pre(); base.Func2; Post(); }
}

Мой вопрос: есть ли более простой способ автоматического создания такого класса, кроме использования отражения в интерфейсе и создания текстового файла с расширением cs?


person Amittai Shapira    schedule 08.12.2010    source источник


Ответы (7)


Лично я бы просто явно регистрировался там, где это необходимо, но если вы настроены на использование декоратора, вы можете использовать класс RealProxy.

Это может выглядеть примерно так:

public class DecoratorProxy<T> : RealProxy
{
    private T m_instance;

    public static T CreateDecorator<T>(T instance)
    {
        var proxy = new DecoratorProxy<T>(instance);
        (T)proxy.GetTransparentProxy();
    }

    private DecoratorProxy(T instance) : base(typeof(T))
    {
        m_instance = instance;

    }
    public override IMessage Invoke(IMessage msg)
    {
        IMethodCallMessage methodMessage = msg as IMethodCallMessage;
        if (methodMessage != null)
        {
            // log method information

            //call method
            methodMessage.MethodBase.Invoke(m_instance, methodMessage.Args);
            return new ReturnMessage(retval, etc,etc);

        }

    }
}
person SpeksETC    schedule 08.12.2010
comment
Сообщение Invoke должно что-то вернуть, поэтому я вернул исходное сообщение. Затем был вызван исходный метод, но я получил следующее исключение: System.Runtime.Remoting.RemotingException : метод был вызван с сообщением неожиданного типа. есть идеи? - person Amittai Shapira; 08.12.2010
comment
Просмотр MSDN (msdn.microsoft.com/ en-us/library/) должен быть возвращен тип IMethodReturnMessage. Как мне просто создать его? - person Amittai Shapira; 08.12.2010
comment
новый ReturnMessage(retval) — см. здесь: msdn .microsoft.com/en-us/library/ - person SpeksETC; 08.12.2010
comment
Спасибо, это помогло. Пожалуйста, отредактируйте свой ответ соответствующим образом... Интересная ссылка: tdanecker.blogspot.com /2007/09/interception-with-proxy.html - person Amittai Shapira; 08.12.2010

Пробовали ли вы использовать PostSharp? Это может помочь вам автоматически «инструментировать» классы и реализовать сценарий ведения журнала без фактического создания декораторов.

person Alex Shtof    schedule 08.12.2010
comment
будьте осторожны с любым инструментом AOP - если вашей компании необходимо соответствие SOX, то это может быть не вариант для вас - person stack72; 08.12.2010
comment
Спасибо, но я хочу что-нибудь бесплатное... Что такое SOX? - person Amittai Shapira; 08.12.2010
comment
У PostSharp есть бесплатная версия для сообщества. Вам не нужно покупать его! Просто перейдите на страницу загрузок. - person Alex Shtof; 08.12.2010

А как насчет блока Logging Application?

http://msdn.microsoft.com/en-us/library/ff647183.aspx

person brumScouse    schedule 08.12.2010
comment
Извините, но мой первоначальный вопрос был не точен - я не веду логи в самом простом смысле. Я делаю некоторую пред- и пост-логику... 1 для этой библиотеки - person Amittai Shapira; 08.12.2010
comment
Учитывая новый опыт, я бы посоветовал людям, приземляющимся здесь, обратить внимание на перехват политики. - person brumScouse; 26.01.2013

Я написал шаблон T4, способный генерировать декоратор для довольно сложных классов на основе некоторых простых соглашений. Проект можно найти на GitHub — T4Decorators. Работает аналогично T4MVC, вот откуда у меня возникла идея.

person Taras Alenin    schedule 07.10.2014

Не могли бы вы использовать T4 и отражение?

Возможно, эти другие вопросы могут помочь:

person Dog Ears    schedule 08.12.2010

У нас такое же требование, и для этого мы написали генератор Roslyn, посмотрите здесь: https://github.com/proactima/ProxyGen Вам нужно немного изменить код, чтобы он соответствовал вашим потребностям. По сути, мы оборачиваем методы интерфейса (все из определенного пространства имен) в метод ReliableServiceCall. Тривиально изменить это, чтобы сделать что-то еще.

person noocyte    schedule 19.02.2016

Лучший подход здесь — использовать шаблон декоратора через интерфейсы. Я знаю, что это очень старый пост, но если вы используете инжектор IoC, такой как SimpleInjector, вы можете настроить эти вызовы декоратора в 1 строке кода. Затем вы можете сделать что-то вроде этого:

public class Decorator : IMyInterface
{ 
     private readonly IMyInterface _next;

     public Decorator (IMyInterface next) { _next = next; }

     public override void Func1() { Pre(); _next.Func1; Post(); }
     public virtual void Func2() { Pre(); _next.Func2; Post(); }
}
person Daniel Lorenz    schedule 04.08.2018
comment
Проблема с этим подходом заключается в том, что каждый раз, когда вы меняете интерфейс, вам придется менять реализацию вашего декоратора (даже если это очень простая реализация). Вот почему этот вопрос специально спрашивал об автоматической генерации, а не о правильном шаблоне для этого... - person Amittai Shapira; 07.08.2018
comment
Если у вас есть общий интерфейс, который используется везде, вы можете сделать это. При этом они определили один интерфейс с несколькими конкретными реализациями, а не собирались реализовывать несколько интерфейсов. Это должно быть хорошо. - person Daniel Lorenz; 07.08.2018