如何使用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存储但没有驱逐。 一般的缓存方面将能够处理方法参数。