2010-07-08 17 views
22

.NET 4.0 ha una buona classe di utilità chiamata System.Lazy che esegue l'inizializzazione di oggetti pigri. Mi piacerebbe usare questa classe per un progetto 3.5. Una volta ho visto un'implementazione da qualche parte in una risposta StackOverflow ma non riesco a trovarla più. Qualcuno ha un'implementazione alternativa di Lazy? Non ha bisogno di tutte le funzionalità di sicurezza del thread della versione 4.0 del framework.Implementazione di Lazy <T> per .NET 3.5

Aggiornato:

risposte contengono un non thread-safe e una versione thread-safe.

risposta

25

Ecco un'implementazione che uso.

+0

Due problemi con questo: Prima di tutto, è preferibile" bloccare "un oggetto privato piuttosto che" bloccare (questo) ", poiché non puoi controllare chi altrimenti potrebbe bloccare l'istanza 'Lazy'. In secondo luogo, non penso che creare "isValueCreated" sia un campo "volatile" utile a qualsiasi scopo quando si sta già utilizzando una sezione critica (vero? Correggimi se sbaglio). – Aaronaught

+0

Accetto volatile viene utilizzato quando il blocco non viene utilizzato. Da MSDN: il modificatore volatile viene solitamente utilizzato per un campo a cui si accede da più thread senza utilizzare l'istruzione lock per serializzare l'accesso. L'utilizzo del modificatore volatile garantisce che un thread recuperi il valore più aggiornato scritto da un altro thread. –

+0

Ho modificato la risposta. –

10

Se non si ha bisogno di thread-safety, è abbastanza facile metterne uno insieme con un metodo factory. Io uso uno molto simile al seguente:

public class Lazy<T> 
{ 
    private readonly Func<T> initializer; 
    private bool isValueCreated; 
    private T value; 

    public Lazy(Func<T> initializer) 
    { 
     if (initializer == null) 
      throw new ArgumentNullException("initializer"); 
     this.initializer = initializer; 
    } 

    public bool IsValueCreated 
    { 
     get { return isValueCreated; } 
    } 

    public T Value 
    { 
     get 
     { 
      if (!isValueCreated) 
      { 
       value = initializer(); 
       isValueCreated = true; 
      } 
      return value; 
     } 
    } 
} 
+0

Chiunque possa copiare questo: può essere facile avere confusione di chiusura con l'inizializzatore qui. Assicurati di catturare i tuoi valori! –

+0

@Rex: Intendi, se stai inizializzando l'istanza 'Lazy ' da un ciclo? 'System.Lazy' fa un po 'di magia per eludere i normali pericoli del catturare? – Aaronaught

+0

un ciclo è un buon esempio. Dubito che il vero 'Lazy' sia diverso, anche se non ne sono sicuro. Ho solo pensato di indicarlo perché vedo che molte persone si mettono nei guai con questo tipo di schema. –

2

Un po 'di semplificare versione di

public class Lazy<T> where T : new() 
{ 
    private T value; 

    public bool IsValueCreated { get; private set;} 

    public T Value 
    { 
    get 
    { 
     if (!IsValueCreated) 
     { 
      value = new T(); 
      IsValueCreated = true; 
     } 
     return value; 
    } 
    } 
} 
+0

Richiede il codificatore predefinito –

+4

@BC: Sì, che è ciò che significa "dove T: new()" significa. –

-1

alcuni divertenti (ma non molto usabile) roba può essere aggiunto di Aaron: coversion implicita da delegato:

public static implicit operator Lazy<T>(Func<T> initializer) 
{ 
    return new Lazy<T>(initializer); 
} 

e l'uso di

private static Lazy<int> Value = new Func<int>(() => 24 * 22); 

Il compilatore C# ha qualche problema con l'esecuzione di questa conversione, ad esempio l'assegnazione di espressione lambda non funziona, ma è un'altra cosa che fa pensare le tue colleghe un po ':)

+0

lambda può essere un albero di espressioni o un delegato in modo che il compilatore rifiuti di considerarli come uno o l'altro. lo stesso motivo per cui non puoi mettere un lambda in una var. Davvero fastidioso a volte ... –

+0

Hai ragione, ma questo codice non funziona anche con i metodi: ' public static int NewValue() { return 24 * 15; } public static Lazy V = NewValue; // Errore di compilazione, necessita di un nuovo Func (NewValue) ' – STO

Problemi correlati