2012-03-02 67 views
3

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

回答

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

Thanfs Dustin。我之前已經閱讀過您的文章,但是我一直很困惑,因爲我將它理解爲特定於IoC的內容,並且看不到像LongOperation這樣的調用會發生在哪裏。我會用新的眼睛仔細觀察。 – remio 2012-03-02 18:19:06

+0

如果您始終要調用相同的方法,請將您的調用更改爲LongOperation。當你想做不同的事情時,問題就出現了,你需要創建不同的方面,或者像服務定位器或工廠那樣使用更通用的方法。 – 2012-03-02 18:37:52

+0

好的,謝謝,這是我懷疑的。的確,我正在尋找一些通用的東西。正如我的問題所提出的,我想實現我的財產,無論哪個方面,然後,可能稍後決定延遲加載其價值。正如nemesv所建議的那樣,.Net4懶惰,但採用AOP方式。 – remio 2012-03-02 20:18:13

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

} 
0

我想的要求不能被準確地描述爲「遲緩裝載」,但是更一般的高速緩存方案的一個特殊的情況下,在-AppDomain中存儲,但沒有驅逐。一般的緩存方面將能夠處理方法參數。