2016-08-24 81 views
0

經過很多次我需要實現一個Lazy<T>模式,它讓我想到了將整個模式放入類中以隱藏延遲實現的想法。封裝懶惰<T>

在「加載單配置對象爲我服務」的情況下,我做了這樣的事情:

public interface IConfigurationProvider<T> 
{ 
    T GetConfiguration(); 
} 

public abstract class SingletonConfigurationProvider<TConfiguration> : IConfigurationProvider<TConfiguration> 
{ 
    private static readonly Lazy<TConfiguration> _lazy = 
     new Lazy<TConfiguration>(_loadConfiguration); 

    private static Func<TConfiguration> _loadConfiguration; 

    private SingletonConfigurationProvider() { } 
    public SingletonConfigurationProvider(Func<TConfiguration> LoadConfig) 
    { 
     _loadConfiguration = LoadConfig; 
    } 

    public TConfiguration GetConfiguration() 
    { 
     return _lazy.Value; 
    } 
} 

我的目標是獲得,從「外部」簡單在做這個:

public class ConfigTest : SingletonConfigurationProvider<ObjectTest> 
{ 
    public ConfigTest() 
     : base(Load) 
    { 
    } 

    public static ObjectTest Load() 
    { 
     return new ObjectTest() 
     { 
      testInt = 3, 
      testString = "Hi" 
     }; 
    } 
} 

的要點是:

  • 它編譯,但它打破了在運行時,用「TypeInitialization例外? n「表示_loadConfiguration不能爲空。是否因爲在構造函數SingletonConfigurationProvider之前構造了懶惰?
  • 是否有可能實現我想要的而不破壞單身人士的語義?
+3

你基本上是圍繞2行代碼構建一個抽象:靜態字段和getter。是不是真的值得嗎? – Sinatr

+1

問題可能出現在_loadConfiguration爲空時初始化_lazy的第一行。嘗試將初始化移動到您的重載構造函數。 – Sarathy

+0

@Sarathy在這種情況下_lazy不能只讀 –

回答

1

您正在尋找的抽象是memoising函數。在這種函數中,您修改了getter函數,以便它實現「只執行一次」類型的模式。未經測試的代碼,但大致;

public Func<T> Memoize(Func<T> slowFunction) { 
    bool evaluated = false; 
    T value = default(T); 

    return() => { 
     if (!evaluated) { 
      value = slowFunction(); 
      evaluated = true; 
     } 

     return value; 
    }; 
} 

所以,你現在有一個功能,你可以這樣使用;

Func<TConfiguration> onceOnlyLoad = Memoise(Load); 

現在,您可以撥打onceOnlyLoad()多次,只要你喜歡,它會只加載的配置第一次調用它。

如果需要,您可以在內部使用Lazy<T>以提供相同的行爲。由你決定。