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

时间:2012-03-02 12:54:10

标签: c# lazy-loading aop 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;
}

3 个答案:

答案 0 :(得分:5)

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

[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(); } }
    }

答案 1 :(得分:1)

感谢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() { }

}

答案 2 :(得分:0)

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