我可以使用装饰器模式来包装方法体吗?

我有一堆不同签名的方法。 这些方法与脆弱的数据连接交互,因此我们经常使用辅助类来执行重试/重新连接等。如下所示:

MyHelper.PerformCall( () => { doStuffWithData(parameters...) }); 

这工作正常,但它可以使代码有点混乱。 我更喜欢做的是装饰与数据连接交互的方法,如下所示:

 [InteractsWithData] protected string doStuffWithData(parameters...) { // do stuff... } 

然后基本上,每当doStuffWithData ,该方法的主体将作为Action传递给MyHelper.PerformCall() 。 我该怎么做呢?

.NET属性是元数据,而不是自动调用的装饰器/活动组件。 没有办法实现这种行为。

您可以使用属性来实现装饰器,方法是将装饰器代码放在Attribute类中,并使用辅助方法调用该方法,该方法使用Reflection调用Attribute类中的方法。 但我不确定这会比直接调用“装饰器方法”有很大改进。

“装饰属性”:

 [AttributeUsage(AttributeTargets.Method)] public class MyDecorator : Attribute { public void PerformCall(Action action) { // invoke action (or not) } } 

方法:

 [MyDecorator] void MyMethod() { } 

用法:

 InvokeWithDecorator(() => MyMethod()); 

助手方法:

 void InvokeWithDecorator(Expression> expression) { // complicated stuff to look up attribute using reflection } 

看看C#中面向方面编程的框架。 这些可能提供你想要的。

所以,我本周末刚刚参加了AOP会议,这里有一种方法可以使用PostSharp:

 [Serializable] public class MyAOPThing : MethodInterceptionAspect { public override void OnInvoke(MethodInterceptionArgs args) { Console.WriteLine("OnInvoke! before"); args.Proceed(); Console.WriteLine("OnInvoke! after"); } } 

然后用[MyAOPThing]装饰方法。 简单!

如果不使用gode生成,就无法对其进行多少操作。 你可能会使语法更好。

但是使用扩展方法呢?

 class static MyHelper { Wrap(this object service, Action action) { // check attribute and wrap call } } 

用法:

 RawFoo foo = ... foo.Wrap(x => x.doStuffWithData(parameters...)); 

这是微不足道的,但你不能确保使用了Wrap。

您可以实现通用装饰器。 这个装饰器将用于包装服务,然后你不能在没有包装的情况下调用它。

 class Decorator { private T implementor; Decorator(T implementor) { this.implementor = implementor; } void Perform(Action action) { // check attribute here to know if wrapping is needed if (interactsWithData) { MyHelper.PerformCall( () => { action(implementor) }); } else { action(implementor); } } } static class DecoratorExtensions { public static Decorator CreateDecorator(T service) { return new Decorator(service); } } 

用法:

 // after wrapping, it can't be used the wrong way anymore. ExtendedFoo foo = rawFoo.CreateDecorator(); foo.Perform(x => x.doStuffWithData(parameters...)); 

这种类型的问题几乎就是AOP(面向方面​​编程)旨在解决的问题。 诸如PostSharp之类的工具可以通过重写编译代码来提供跨领域的关注。 Scott Hanselman的播客最近讨论了AOP,所以值得倾听。

查看面向方面的框架 。 但请注意,虽然它们隐藏了每种方法的复杂性,但AoPfunction的存在可能会使您的程序难以维护。 这是一个权衡。

看起来你想要的是类似于IoC容器或测试运行器框架的行为,它实际上并不是从程序集执行,而是运行围绕代码构建的动态发出的程序集。 (比我在其他答案中称之为AOP更聪明的人)

因此,也许在您的应用程序的存根中,您可以扫描其他程序集,构建那些发出的程序集(使用装饰方法的主体调用MyHelper.PerformCall),然后您的程序将针对发出的代码运行。

在没有评估一些现有的AOP框架是否可以实现您所需要的东西的情况下,我决不会开始尝试编写此文章。 HTH>

看到你愿意为每个需要它的方法添加一行代码,为什么不在这个方法本身内调用MyHelper呢?

 protected string doStuffWithData(parameters...) { MyHelper.PerformCall( () => { doStuffWithDataCore(parameters...) }); } private string doStuffWithDataCore(parameters...) { //Do stuff here }