6

假设我有一个返回Posts 列表的存储库。存储库接口有一个GetAll()方法可以执行它的建议。

现在按照我不应该将域逻辑放入存储库的理论,我想拦截对具体GetAll()方法的调用,以便我可以将以下逻辑添加到GetAll()结果中:

return GetAll().OrderByDescending(p => p.Posted).ToList();

我想拦截它的原因是因为(1)我不想让客户端记住调用扩展方法(OrderByDescending或一些无用的包装器),我希望每次都调用它并且(2)我不希望我的所有具体实现都必须记住对GetAll()结果进行排序-我希望将此逻辑放在任何存储库外部的单个位置。

最简单的方法是什么?

我已经在使用StructureMap,所以如果我可以用它拦截它可能是一个低成本的选择。但我不认为 SM 拦截方法调用,只是对象实例的创建?

我需要使用代理或混合模式吗?我需要全力以赴使用 Castle Dynamic Proxy吗?还是我应该考虑另一种方法或组合?

我对我上面的特定示例的具体建议非常感兴趣。我是 AOP 的新手,所以请温柔一点。

4

4 回答 4

13

使用DynamicProxy选项。它比我想象的更容易使用。

所需要的只是using Castle.DynamicProxy;参考...

有点IInterceptor...

public class PostRepoInterceptor : IInterceptor
{
    public void Intercept(IInvocation invocation)
    {
        invocation.Proceed();

        if (invocation.Method.Name.Equals("GetAll", StringComparison.InvariantCultureIgnoreCase))
            invocation.ReturnValue = this.GetModifiedGetAllResult(invocation.ReturnValue);
    }

    private object GetModifiedGetAllResult(object getAllResult)
    {
        return Post.GetOrderedPosts((IList<Post>)getAllResult);
    }
}

StructureMap 配置中的两个新行:

    public RepoRegistry()
    {
        var pg = new ProxyGenerator();

        For<IPostRepository>()
            .EnrichAllWith(z => pg.CreateInterfaceProxyWithTarget<IPostRepository>(z, new PostRepoInterceptor()));
    }

..它完成了。GetAll()现在表现出我想要的样子。我仍然可以以我熟悉的方式使用这些接口,并且我已经将其保持为 DRY 并为 DDD 解耦。

感谢山姆安德烈

于 2010-12-23T07:11:20.130 回答
2

AFAIK,StructureMap 只拦截对象构造,所以使用它是行不通的。

我不知道 Castle,但我认为这里的想法是应用Decorator 模式,因此您也可以按照上一个链接中描述的步骤自行完成,而无需重复使用第三方库。

我就是这样做的,因为我不是 AOP 的忠实粉丝。

高温高压

于 2010-12-21T08:57:22.643 回答
0

不,它不能改变返回值。但是,您可以访问目标内部方面来更改目标的属性。假设您已经定义了存储库,这里是添加后处理方面以更改目标属性的代码。

IRepository<decimal> Rep = new Repository();
IRepository<decimal> tpRep = (IRepository<decimal>)ObjectProxyFactory.CreateProxy(Rep,
new String[] { "GetAll" },
null,
new Decoration((x, y) =>
{
    Console.WriteLine("Entering " + x.GetType().ToString());
    if (x.GetType().ToString() == "ThirdPartyHR.Repository")
    {
        List<decimal> decimals = ((Repository)x).RepList;
        IEnumerable<decimal> query = decimals.OrderByDescending(num => num, new SpecialComparer()).ToList<decimal>();
        ((Repository)x).RepList = (List<decimal>)query;
    }
}, null));
tpRep.GetAll();
List<decimal> lstRep = Rep.RepList;

如果需要,我可以向您发送完整的工作代码。并且,如果可能,请从“使用动态装饰器向对象添加方面”一文中回复我,因为我不会在此处自动收到消息。

于 2011-01-17T21:26:43.660 回答
-1

有一篇文章Add Aspects to Object Using Dynamic Decorator

它描述了一种在运行时向对象添加方面而不是在设计时向类添加方面的方法。看起来这就是你想要的。

于 2011-01-15T12:41:50.017 回答