如何使用PostSharp实现延迟加载?

我想用PostSharp在属性上实现延迟加载。

简而言之,而不是写作

SomeType _field = null; private SomeType Field { get { if (_field == null) { _field = LongOperation(); } return _field; } } 

我想写

 [LazyLoadAspect] private object Field { get { return LongOperation(); } } 

所以,我确定我需要在类中发出一些代码来生成支持字段,以及在getter方法中为了实现测试。

使用PostSharp,我正在考虑重写CompileTimeInitialize ,但我错过了处理已编译代码的知识。

编辑:问题可以扩展到任何无参数的方法,如:

 SomeType _lazyLoadedField = null; SomeType LazyLoadableMethod () { if(_lazyLoadedField ==null) { // Long operations code... _lazyLoadedField = someType; } return _lazyLoadedField ; } 

会成为

 [LazyLoad] SomeType LazyLoadableMethod () { // Long operations code... return someType; } 

在我们的评论之后,我想我现在知道你想要什么。

 [Serializable] public class LazyLoadGetter : LocationInterceptionAspect, IInstanceScopedAspect { private object backing; public override void OnGetValue(LocationInterceptionArgs args) { if (backing == null) { args.ProceedGetValue(); backing = args.Value; } args.Value = backing; } public object CreateInstance(AdviceArgs adviceArgs) { return this.MemberwiseClone(); } public void RuntimeInitializeInstance() { } } 

测试代码

 public class test { [LazyLoadGetter] public int MyProperty { get { return LongOperation(); } } } 

感谢DustinDavis的回答和评论,我可以自己实施,我只想在这里分享它以帮助其他人。

与原答案的主要区别在于:

  • 实现建议“只运行一次操作”(锁的目的)
  • 通过将此职责传递给boolean ,使备份字段的初始化状态更可靠。

这是代码:

 [Serializable] public class LazyLoadAttribute : LocationInterceptionAspect, IInstanceScopedAspect { // Concurrent accesses management private readonly object _locker = new object(); // the backing field where the loaded value is stored the first time. private object _backingField; // More reliable than checking _backingField for null as the result of the loading could be null. private bool _hasBeenLoaded = false; public override void OnGetValue(LocationInterceptionArgs args) { if (_hasBeenLoaded) { // Job already done args.Value = _backingField; return; } lock (_locker) { // Once the lock passed, we must check if the aspect has been loaded meanwhile or not. if (_hasBeenLoaded) { args.Value = _backingField; return; } // First call to the getter => need to load it. args.ProceedGetValue(); // Indicate that we Loaded it _hasBeenLoaded = true; // store the result. _backingField = args.Value; } } public object CreateInstance(AdviceArgs adviceArgs) { return MemberwiseClone(); } public void RuntimeInitializeInstance() { } } 

我认为这个要求不能准确地描述为“延迟加载”,但是这是一个特殊情况,它具有更广泛的缓存方面,具有in-AppDomain存储但没有驱逐。 一般的缓存方面将能够处理方法参数。