How to implement Lazy loading with PostSharp?

谁说胖子不能爱 提交于 2019-12-06 08:02:07

问题


I would like to implement lazy loading on properties with PostSharp.

To make it short, instead of writing

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

I would like to write

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

So, I identify that I need to emit some code in the class to generate the backing field, as well as inside the getter method in order to implement the test.

With PostSharp, I was considering overriding CompileTimeInitialize, but I am missing the knowledge to get a handle over the compiled code.

EDIT: The question can be extended to any parameterless method like:

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

would become

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

回答1:


After our comments, I think I know what you want now.

[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()
        {

        }
    }

Test code

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



回答2:


Thanks to DustinDavis's answer and comments, I could work on my own implementation, and I just wanted here to share it to help other people.

The main differences from the original answer are:

  • Implement the suggested "only run the operation once" (purpose of the lock)
  • Made the initialization status of the backing field more reliable by passing this responsibility to a boolean.

Here is the code:

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

}



回答3:


I think the requirement cannot be accurately described as 'lazy loading', but is a special case of a more general caching aspect with in-AppDomain storage but without eviction. A general caching aspect would be able to handle method parameters.



来源:https://stackoverflow.com/questions/9533656/how-to-implement-lazy-loading-with-postsharp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!