为什么要使用后期编译器?

Rob*_*ean 8 postsharp

我正在努力理解为什么需要像PostSharp这样的后期编译器?

我的理解是它只是在原始代码中插入代码,所以为什么开发人员不会自己编写代码呢?

我希望有人会说它更容易编写,因为你可以使用方法上的属性,然后不会混淆它们的样板代码,但这可以使用DI或反射和没有后编译器的预先考虑.我知道,因为我已经说过反射,性能大象现在会进入 - 但我不关心这里的相对性能,当大多数场景的绝对性能是微不足道的(亚毫秒到毫秒).

Gae*_*eur 22

让我们尝试在这个问题上采取架构点.假设您是一名架构师(每个人都想成为一名架构师;)您需要为您的团队提供架构:一组选定的库,架构模式和设计模式.作为设计的一部分,您说:"我们将使用以下设计模式实现缓存:"

string key = string.Format("[{0}].MyMethod({1},{2})", this, param1, param2 );
T value;
if ( !cache.TryGetValue( key, out value ) )
{
   using ( cache.Lock(key) )
   {
      if (!cache.TryGetValue( key, out value ) )
      {
         // Do the real job here and store the value into variable 'value'.
         cache.Add( key, value );
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

这是一种正确的跟踪方式.开发人员将实现这种模式数千次,因此您编写了一个很好的Word文档,告诉您希望如何实现该模式.是的,Word文档.你有更好的解决方案吗?我怕你没有.经典代码生成器无济于事.功能编程(代表)?它在某些方面工作得相当好,但不是在这里:你需要将方法参数传递给模式.那剩下什么了?用自然语言描述模式,开发人员将信任它们.

会发生什么?

首先,一些初级开发人员将查看代码并告诉"Hm.两个缓存查找.有点无用.一个就够了." (这不是一个笑话 - 向DNN团队询问此问题).而且你的模式不再是线程安全的.

作为架构师,您如何确保正确应用模式?单元测试?很公平,但你很难用这种方式检测线程问题.代码审查?那可能是解决方案.

现在,你决定改变模式是什么?例如,您检测到缓存组件中的错误并决定使用自己的错误?你要编辑成千上万的方法吗?它不仅仅是重构:如果新组件具有不同的语义,该怎么办?

如果您决定不再缓存某个方法,该怎么办?删除缓存代码有多难?

AOP解决方案(无论框架是什么)与普通代码相比具有以下优势:

  1. 减少了代码行数.
  2. 减少了组件之间的耦合,因此当您决定更改日志记录组件(只更新方面)时,您不必更改太多内容,因此它可以提高源代码的能力,以便随着时间的推移处理新的需求.
  3. 由于代码较少,因此对于给定的一组功能,错误的可能性较低,因此AOP 可以提高代码的质量.

所以,如果你把它们放在一起:

方面降低了软件的开发成本和维护成本.

关于这个主题,我有90分钟的谈话,您可以在http://vimeo.com/2116491上观看.

同样,AOP的架构优势与您选择的框架无关.框架之间的差异(也在本视频中讨论)主要影响您将AOP应用于代码的程度,这不是这个问题的重点.


Jon*_*eet 11

假设您已经拥有一个经过精心设计,经过良好测试等的类.您希望在某些方法上轻松添加一些时序.是的,您可以使用依赖注入,创建一个代理原始但与每个方法的时间相关的装饰器类 - 但即使该类也将是一堆重复......

...或者您可以在混音中添加反射并使用某些描述的动态代理,这可以让您编写一次定时代码,但需要您将反射代码恰到好处 - 这并不像它可能那么容易,特别是如果涉及泛型.

...或者你可以为你想要定时的每个方法添加一个属性,编写一次定时代码,并将其作为后编译步骤应用.

我知道哪个看起来更优雅 - 在阅读代码时更明显.它甚至可以在情况下DI应用适合(它确实不适合每一个系统中的单个类)和其他地方没有其他变化.

  • @silky:是的,但他们并不总是合适的.例如,我不希望有一个在生产作业上运行,而精心选择的方法*的轻量级计时/记录可以*用于生产,因此您可以从实际情况中获得真实数据. (2认同)
  • @罗伯特:不,一点也不。我不相信 DI 是所有问题的最佳答案,即使它可以是 *a* 解决方案。我自己并不怎么使用 AOP,但我可以看到它的好处。 (2认同)
  • @Robert:你假设你*只在输入时才想要它.我同意这很容易.什么时候它也退出 - 在所有情况下,包括抛出异常时.指示它是否正常退出也是有用的.现在你手动完成的1行显着增长 - 但属性解决方案仍然是1行.至于重新测试它 - 你测试所有的诊断记录吗?我知道我不...这对我来说似乎是浪费时间. (2认同)

Noo*_*ilk 5

AOP (PostSharp) 用于将代码从一个位置附加到应用程序中的各种点,因此您不必将其放置在那里。

您无法实现 PostSharp 使用 Reflection 所做的事情。

我个人认为它在生产系统中没有太大用处,因为大多数事情都可以通过其他更好的方式(日志记录等)完成。

您可能想查看有关此问题的其他主题: