2012-03-28 12 views
5

Ho un sacco di pezzi di codice che devono essere eseguiti una volta durante l'inizializzazione.Esecuzione di un fusibile con una booleana

devo usare un flag booleano in questo modo, perché è in un evento

bool _fuse; 

void PerformLayout() 
{ 
    Size size; 

    if (!_fuse) 
    { 
     size = _InitialContainerSize; 
     _fuse = true; 
    } 
    else 
     size = parent.Size; 

    // ... 
} 

Perché spesso accade, ho fatto qualcosa per rendere questa variabile booleana a guardare come un fusibile:

Così ho fatto questo:

bool _fuse; 

void PerformLayout() 
{ 
    Size size; 

    if (!Burnt(ref _fuse)) 
     size = _InitialContainerSize; 
    else 
     size = parent.Size; 

    // ... 
} 

Se viene inizializzato su false, il risultato della query restituisce falso una volta, fare la switc h su true e le chiamate successive restituiscono true.

public static bool Burnt(ref bool value) 
{ 
    if (!value) 
    { 
     value = true; 
     return false; 
    } 
    else 
     return true; 
} 

Naturalmente, funziona, ma sono solo moderatamente soddisfatto e sono sicuro che ci sia soluzioni più eleganti. Quale sarebbe il tuo?

+2

'valore restituito || ! (value = true); '(sto scherzando!) –

+0

Interessante. Finora il conto è composto da tre upvotes e tre voti da chiudere. –

+0

Non è una domanda reale. Dovrebbe essere su un sito di codeview. Non qui. – leppie

risposta

1

Credo che l'impostazione generale ad evitare la ripetizione qui è giusto (anche se la ripetizione è molto piccolo ... ma ancora). Basta incapsulare e il nome corretto:

struct InitializerGuard { 
    private bool hasRun; 

    public bool HasRun() { 
     if (hasRun) 
      return true; 
     hasRun = true; 
     return false; 
    } 
} 

Usage:

InitializerGuard sizeInitializer; 

void PerformLayout() 
{ 
    Size size; 

    if (!sizeInitializer.HasRun()) 
     size = _InitialContainerSize; 
    else 
     size = parent.Size; 

    // ... 
} 

Ma se vi trovate a utilizzare questo modello molto spesso questo potrebbe indicare che un refactoring è in ordine. Forse basta assegnare valori predefiniti ad alcune variabili? Perché non sono inizializzati, comunque?

+1

o semplicemente: 'Dimensione dimensione = HasRun()? parent.Size: _initSize; ' – leppie

+0

Questo è elegante e CHIARO. Mi piace. Penso che lo copierò. (forse cambierò il metodo HasRun in una proprietà invece?) - Potrei forse rifattare una parte del mio codice in modo migliore, ma in molti casi non ho scelta perché è usato in alcuni eventi, e il codice arount richiede qualche init al loro primo fuoco. – Larry

+1

@Laurent Properties non deve avere effetti collaterali. Per lo meno, questo rovina il tuo debugger (se esegui il debug del tuo codice e aggiungi un watch per questa variabile, la proprietà viene valutata in momenti arbitrari, cambiando così il tuo comportamento). Quindi se rendi questa proprietà, interrompi il tuo codice in modi "interessanti". ;-) –

1

È possibile utilizzare i tipi nullable e l'operatore null coalescenza per dichiarare una proprietà Size:

Size? _containerSize; 

Size ContainerSize { 
    get { 
    return (_containerSize ?? (_containerSize = _InitialContainerSize)).Value; 
    } 
} 

è possibile utilizzare in questo modo:

void PerformLayout() { 
    var size = ContainerSize; 
    // ... 
} 

Se il tipo che si desidera inizializzare pigro è un tipo di riferimento diventa ancora più semplice.

Un'altra opzione è utilizzare il tipo Lazy<T>. Questo può essere utilizzato in scenari multi-threading in cui il codice sopra può interrompere:

Lazy<Size> _containerSize = new Lazy<Size>(() => _InitialContainerSize); 

void PerformLayout() { 
    var size = _containerSize.Value; 
    // ... 
} 
1

Ci sono molti modi per raggiungere questo obiettivo. È possibile creare una macchina a stati complessa che esegua la logica (più veloce) ma che in molti casi sarà eccessiva. In alternativa, puoi tenere traccia di un valore booleano che mantiene lo stato della tua istanza proprio come hai ora. Si può anche decidere di combinare entrambe le soluzioni in una semplice macchina a stati con metodi come (moderatamente veloce):

public class TestClass 
{ 
    private Action performLayoutAction; 

    public TestClass() 
    { 
     // initial state 
     performLayoutAction = InitializePeformLayout; 
    } 

    public void PerformLayout() 
    { 
     performLayoutAction(); 
    } 

    private void InitializePeformLayout() 
    { 
     // whatever 

     performLayoutAction = ContiniousPerformLayout; 
    } 

    private void ContiniousPerformLayout() 
    { 
     // whatever 
    } 
}