我可以使用装饰器模式来包装方法体吗?
我有一堆不同签名的方法。 这些方法与脆弱的数据连接交互,因此我们经常使用辅助类来执行重试/重新连接等。如下所示:
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 }