DispatchProxy
От: vaa  
Дата: 05.09.21 12:06
Оценка:
    public interface IDoer
    {
        IDoer Hello();
        IDoer GoodBye();
    }
    public static class DoerExtensions
    {
        public static IDoer Welcome(this IDoer it)
        {
            WriteLine("Welcome");
            return it;
        }
    }
    public class Doer : IDoer
    {
        public IDoer Hello()
        {
            WriteLine("Hello");
            return this;
        }

        public IDoer GoodBye()
        {
            WriteLine("Goodbye");
            return this;
        }
    }

    public class DoerProxy : DispatchProxy
    {
        public IDoer Target { get; private set; }
        public static IDoer Decorate(IDoer target = null)
        {
            var proxy = Create<IDoer, DoerProxy>() as DoerProxy;
            proxy.Target = target ?? Activator.CreateInstance<Doer>();
            return proxy as IDoer;
        }
        protected override object Invoke(MethodInfo targetMethod, object[] args)
        {
            Write("Proxy call: ");
            return targetMethod.Invoke(Target, args);
        }
    }
...........................
 IDoer doer = new Doer();
            WriteLine("core proxy:");
            IDoer doerCore = DoerProxy.Decorate(doer);
            _ = doerCore.Hello().GoodBye().Welcome(); // <= 
            _ = doerCore.Hello();
            _ = doerCore.Welcome(); 
            _ = doerCore.GoodBye();

вывод:

Proxy call: Hello
Goodbye
Welcome
Proxy call: Hello
Welcome
Proxy call: Goodbye
Castle proxy:


Вопрос в следующем: то, что при цепочном вызове методов интерфейса прокси перехватывает только первый это баг или фича?
Для меня это как минимум было неприятной неожиданностью. Можно изменить поведение прокси?

Быть может с помощью Castle.DynamicProxy?
Вот такой код не справился с задачей(аналогично коровской реализации).
public class DoerCastleProxy : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            Write("Castle call: ");
            invocation.Proceed();
        }
    }
......
 ProxyGenerator generator = new ProxyGenerator();
            IDoer doerCastle = generator.CreateInterfaceProxyWithTargetInterface<IDoer>(doer, new DoerCastleProxy());
            _ = doerCastle.Hello().GoodBye().Welcome();


PS расширение включил в код без особых надежд, хотя он как бы должен расширять интерфейс, но не является его частью.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Отредактировано 05.09.2021 12:12 Разраб . Предыдущая версия . Еще …
Отредактировано 05.09.2021 12:06 Разраб . Предыдущая версия .
Re: DispatchProxy
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 05.09.21 13:27
Оценка: 8 (1)
Здравствуйте, vaa, Вы писали:


vaa>
vaa>    public interface IDoer
vaa>    {
vaa>        IDoer Hello();
vaa>        IDoer GoodBye();
vaa>    }
vaa>    public static class DoerExtensions
vaa>    {
vaa>        public static IDoer Welcome(this IDoer it)
vaa>        {
vaa>            WriteLine("Welcome");
vaa>            return it;
vaa>        }
vaa>    }
vaa>    public class Doer : IDoer
vaa>    {
vaa>        public IDoer Hello()
vaa>        {
vaa>            WriteLine("Hello");
vaa>            return this;
vaa>        }

vaa>        public IDoer GoodBye()
vaa>        {
vaa>            WriteLine("Goodbye");
vaa>            return this;
vaa>        }
vaa>    }

vaa>    public class DoerProxy : DispatchProxy
vaa>    {
vaa>        public IDoer Target { get; private set; }
vaa>        public static IDoer Decorate(IDoer target = null)
vaa>        {
vaa>            var proxy = Create<IDoer, DoerProxy>() as DoerProxy;
vaa>            proxy.Target = target ?? Activator.CreateInstance<Doer>();
vaa>            return proxy as IDoer;
vaa>        }
vaa>        protected override object Invoke(MethodInfo targetMethod, object[] args)
vaa>        {
vaa>            Write("Proxy call: ");
vaa>            return targetMethod.Invoke(Target, args);
vaa>        }
vaa>    }
vaa>...........................
vaa> IDoer doer = new Doer();
vaa>            WriteLine("core proxy:");
vaa>            IDoer doerCore = DoerProxy.Decorate(doer);
vaa>            _ = doerCore.Hello().GoodBye().Welcome(); // <= 
vaa>            _ = doerCore.Hello();
vaa>            _ = doerCore.Welcome(); 
vaa>            _ = doerCore.GoodBye();
vaa>

vaa>вывод:
vaa>

vaa>Proxy call: Hello
vaa>Goodbye
vaa>Welcome
vaa>Proxy call: Hello
vaa>Welcome
vaa>Proxy call: Goodbye
vaa>Castle proxy:


vaa>Вопрос в следующем: то, что при цепочном вызове методов интерфейса прокси перехватывает только первый это баг или фича?

vaa>Для меня это как минимум было неприятной неожиданностью. Можно изменить поведение прокси?

vaa>Быть может с помощью Castle.DynamicProxy?

vaa>Вот такой код не справился с задачей(аналогично коровской реализации).
vaa>
vaa>public class DoerCastleProxy : IInterceptor
vaa>    {
vaa>        public void Intercept(IInvocation invocation)
vaa>        {
vaa>            Write("Castle call: ");
vaa>            invocation.Proceed();
vaa>        }
vaa>    }
vaa>......
vaa> ProxyGenerator generator = new ProxyGenerator();
vaa>            IDoer doerCastle = generator.CreateInterfaceProxyWithTargetInterface<IDoer>(doer, new DoerCastleProxy());
vaa>            _ = doerCastle.Hello().GoodBye().Welcome();
vaa>


vaa>PS расширение включил в код без особых надежд, хотя он как бы должен расширять интерфейс, но не является его частью.


Ну по уму ты должен сделать оберту и в

protected override object Invoke(MethodInfo targetMethod, object[] args)
       {
            Write("Proxy call: ");
            var result = targetMethod.Invoke(Target, args);
if (result is IDoer d)
{
var proxy = Create<IDoer, DoerProxy>() as DoerProxy;
    proxy.Target = d;
return proxy;
}
return result;
}
        }
и солнце б утром не вставало, когда бы не было меня
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.