【问题标题】:How to dynamically decorate a class?如何动态装饰一个类?
【发布时间】:2013-01-23 19:06:03
【问题描述】:

我有一个简单的装饰器类,如下所示。请注意我的公共方法是如何创建待装饰类的新实例,然后将调用转发到该实例的。

这个类的问题是,每当IMyService 更新时,我也必须更新这个代理类。

public class MyProxyService : IMyService
{
    readonly IMyServiceFactory _realServiceFactory;

    public MyProxyService(IMyServiceFactory realServiceFactory)
    {
        _realServiceFactory = realServiceFactory;
    }

    private IMyService CreateRealService()
    {
        return _realServiceFactory.CreateRealService();
    }

    public int A()
    {
        return CreateRealService().A();
    }

    public int B(int b1)
    {
        return CreateRealService().B(int b1);
    }

    public int C(int c1, int c2)
    {
        return CreateRealService().C(c1,c2);
    }

    public int D(int d1, int d2, int d3)
    {
        return CreateRealService().D(d1,d2,d3);
    }
    public void E()
    {
        CreateRealService().E();
    }
}

我尝试使用Castle.DynamicProxy 创建动态版本,但到目前为止没有任何运气。

有人知道动态创建这样的装饰器的好方法吗?

【问题讨论】:

  • 嗯,动态代理是个不错的选择。你能告诉我们你尝试了什么吗?
  • 我发现装饰模式非常费力,而且完全不会重新措辞,特别是如果接口匹配 1:1 就像你的情况一样。您能否提供一些背景,为什么您需要这样的代理您的场景和问题是什么。我知道这不是回答您的问题所必需的,但我想知道。
  • @Kirk Woll:我真的不知道我在用 DynamicProxy 做什么,所以我无法显示任何有用的代码。我尝试创建一个拦截器并在拦截时更改其调用目标,但 InvocationTarget 是只读的。
  • @Rafal:我将它们用于各种事情,上面代码背后的想法是延迟加载对象和延迟加载远程服务代理。效果很好,但我不想每次服务接口更改时都更改装饰器。

标签: c# decorator castle-dynamicproxy


【解决方案1】:

我能够使用 DynamicProxy.ProxyGenerator's CreateInterfaceProxyWithTargetInterface(..) 让它工作。

我首先创建了一个动态代理工厂。这会返回一个代理对象,每个方法都会被提供的IInterceptor拦截:

public class MyDynamicallyDecoratedServiceClientFactory
{
    readonly ProxyGenerator _proxyGenerator;
    readonly IInterceptor _interceptor;
    public MyServiceClientFactory(IInterceptor interceptor)
    {
        _interceptor = interceptor;
        _proxyGenerator = new ProxyGenerator();
    }
    public IMyService Create()
    {
        IMyService proxy = _proxyGenerator.CreateInterfaceProxyWithTargetInterface<IMyService>(null, _interceptor);
        return proxy;
    }
}

然后我实现了拦截器。在每次方法调用时,都会调用此拦截器,它将从提供的IMyServiceFactory 创建一个新的IMyService,并将方法调用委托给该新实例。

public class MyServiceClientInterceptor : IInterceptor
{
    readonly IMyServiceFactory _svcFactory;
    public MyServiceClientInterceptor(IMyServiceFactory svcFactory)
    {
        _svcFactory = svcFactory;
    }
    public void Intercept(IInvocation invocation)
    {
        IMyService realService = _svcFactory.Create();
        IChangeProxyTarget changeProxyTarget = invocation as IChangeProxyTarget;
        changeProxyTarget.ChangeInvocationTarget(realService);
        invocation.Proceed();
    }
}

最后,利用这一切:

// Create a service factory (the to-be-decorated class)
IMyServiceFactory myRealServiceFactory = /* ... */;

// Create a factory that will create decorated services
MyServiceClientInterceptor interceptor = 
        new MyServiceClientInterceptor(myRealServiceFactory);
MyDynamicallyDecoratedServiceClientFactory svcFactory =  
        new MyDynamicallyDecoratedServiceClientFactory(interceptor);

// Create a service client
IMyService svc = svcFactory.Create();

// Use it!
svcProxy.A();

【讨论】:

    猜你喜欢
    • 2020-02-03
    • 1970-01-01
    • 2022-01-09
    • 2017-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-04
    • 2017-06-02
    相关资源
    最近更新 更多