如何使用PostSharp实现懒惰加载
本文关键字:加载 实现 何使用 PostSharp | 更新日期: 2023-09-27 18:26:39
我想用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() { }
}
我认为这个需求不能准确地描述为"延迟加载",而是一个更通用的缓存方面的特殊情况,具有AppDomain中的存储,但没有驱逐。一个通用的缓存方面将能够处理方法参数。