2012-03-28 20 views
5

Mam wiele kawałków kodu, które muszą być uruchamiane jeden raz podczas inicjowania.Ładowanie bezpiecznika z boolean

muszę użyć flagi wartości logicznej, w ten sposób, ponieważ jest to w przypadku

bool _fuse; 

void PerformLayout() 
{ 
    Size size; 

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

    // ... 
} 

Ponieważ zdarza się często, zrobiłem coś, aby ta zmienna boolean wyglądać jak bezpiecznikiem:

Więc zrobiłem tak:

bool _fuse; 

void PerformLayout() 
{ 
    Size size; 

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

    // ... 
} 

Jeśli jest inicjowane fałszywy wynik zapytania zwraca false raz dokonać switc h do prawdziwego, a kolejne połączenia zwracają prawdę.

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

Oczywiście działa, ale jestem tylko umiarkowanie zadowolony i jestem pewien, że są bardziej eleganckie rozwiązania. Jaki byłby twój?

+2

'wartość zwracana || ! (value = true); '(tylko żartuję!) –

+0

Interesujące. Do tej pory liczy się trzy przegrane i trzy głosy do zamknięcia. –

+0

To nie jest prawdziwe pytanie. Powinien być na stronie codereview. Nie tutaj. – leppie

Odpowiedz

1

myślę, że ogólny kierunek w uniknięciu powtórki tutaj ma rację (nawet jeśli powtarzanie jest bardzo mały ... ale nadal). Wystarczy ująć go i nazwać go poprawnie:

struct InitializerGuard { 
    private bool hasRun; 

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

Zastosowanie:

InitializerGuard sizeInitializer; 

void PerformLayout() 
{ 
    Size size; 

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

    // ... 
} 

Ale jeśli znajdziesz się stosując ten wzór bardzo często może to wskazywać, że refaktoryzacji jest w porządku. Może po prostu przypisz wartości domyślne do niektórych zmiennych? Dlaczego zresztą nie są one inicjowane?

+1

lub po prostu: "Rozmiar size = HasRun()? parent.Size: _initSize; ' – leppie

+0

To jest eleganckie i CZYSTE. Lubię to. Myślę, że to skopiuję. (może zamiast tego zmienię metodę HasRun na właściwość?) - prawdopodobnie mógłbym poprawić część mojego kodu lepiej, ale w wielu przypadkach nie mam wyboru, ponieważ jest on używany w niektórych zdarzeniach, a kod arount wymaga jakiegoś init na ich pierwszy ogień. – Larry

+1

@Laurent Właściwości nie mogą mieć skutków ubocznych. Co najmniej, to wkręca twój debugger (jeśli debugujesz swój kod i dodajesz zegarek dla tej zmiennej, właściwość jest oceniana w dowolnym momencie, zmieniając twoje zachowanie). Jeśli więc stworzysz tę właściwość, złamiesz swój kod w "interesujący" sposób. ;-) –

1

Można użyć zerowalne typów i zerowej operatora koalescencyjny zadeklarować Size właściwość:

Size? _containerSize; 

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

Następnie można go używać tak:

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

Jeśli typ chcesz leniwe initialize jest typem odniesienia, staje się jeszcze prostsze.

Inną opcją jest użycie typu Lazy<T>. Może to być używane w scenariuszach wielowątkowych, w których powyższy kod może zostać złamany:

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

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

Istnieje wiele sposobów osiągnięcia tego. Możesz utworzyć złożoną maszynę stanu wykonującą swoją logikę (najszybszą), ale w wielu przypadkach będzie to przesada. Alternatywnie możesz śledzić wartość logiczną, która utrzymuje stan instancji dokładnie tak, jak teraz. Można również zdecydować się połączyć oba rozwiązania w prosty machiny państwowej z metod, takich jak (umiarkowanie szybko):

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 
    } 
}