【问题标题】:How to implement Lazy loading with PostSharp?如何使用 PostSharp 实现延迟加载?
【发布时间】:2012-03-02 12:54:09
【问题描述】:

我想用 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;
}

【问题讨论】:

    标签: c# lazy-loading aop postsharp


    【解决方案1】:

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

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

    【讨论】:

    • 感谢达斯汀。我之前已经阅读过你的文章,但我一直很困惑,因为我理解它是非常特定于 IoC 的,并且看不到像 LongOperation 这样的调用会发生在哪里。我会用新的眼光仔细观察它。
    • 如果您总是要调用相同的方法,那么将 IoC 的内容替换为对 LongOperation 的调用。当您想做不同的事情时,问题就来了,您需要创建不同的方面或使用更通用的东西,例如服务定位器或工厂。
    • 好的,谢谢,这就是我的怀疑。确实,我在寻找通用的东西。正如我的问题中所提出的,我想实现我的属性而不考虑方面,然后,可能稍后决定延迟加载它的值。正如 nemesv 建议的那样,与 .Net4 Lazy 完全一样,但采用 AOP 方式。
    • @remio 延迟加载是延迟操作(通常是因为它长时间运行)直到实际请求资源的行为。目的是等到实际需要某些东西后再花时间初始化它。如果从未请求过资源,则它不会被初始化。缓存是操作结果的存储。目的是只运行一次操作(尤其是长时间运行时)。任何后续请求都将通过传递实际操作返回存储的值。
    • @remio 从技术上讲,您要编写的代码是延迟加载的,它在被请求之前不会被初始化。但是每次发出请求时都会调用该操作,这是您想要避免的,因此您需要缓存来存储结果并避免后续请求中的操作。非常细微的区别。
    【解决方案2】:

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

    与原始答案的主要区别是:

    • 实施建议的“只运行一次操作”(锁定的目的)
    • 将此职责传递给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() { }
    
    }
    

    【讨论】:

      【解决方案3】:

      我认为该要求不能准确地描述为“延迟加载”,而是具有应用程序域内存储但没有驱逐的更通用缓存方面的特例。一般缓存方面将能够处理方法参数。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-01-20
        • 2019-04-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多