2012-03-28 7 views
5

Tengo un montón de códigos que deben ejecutarse una vez durante la inicialización.Hacer un fusible con un booleano

tengo que usar una bandera booleana de esta manera porque está en un evento

bool _fuse; 

void PerformLayout() 
{ 
    Size size; 

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

    // ... 
} 

porque sucede a menudo, me hizo algo para que esta variable booleana para que parezca un fusible:

Así que hice esto:

bool _fuse; 

void PerformLayout() 
{ 
    Size size; 

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

    // ... 
} 

Si se inicializa en false, el resultado de la consulta devuelve falsa una vez, hacer que el switc h verdadero, y las llamadas sucesivas devuelven verdadero.

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

Por supuesto, funciona, pero solo estoy moderadamente satisfecho y estoy seguro de que hay soluciones más elegantes. ¿Cuál sería el tuyo?

+2

'valor de retorno || ! (value = true); '(es una broma!) –

+0

Interesante. Hasta ahora, el recuento es de tres votaciones y tres votos para cerrar. –

+0

No es una pregunta real. Debería estar en un sitio de revisión de código. Aqui no. – leppie

Respuesta

1

Creo que la tendencia general a evitar la repetición aquí es correcto (incluso si la repetición es muy pequeña ... pero todavía) Sólo encapsular y nombrar correctamente:

struct InitializerGuard { 
    private bool hasRun; 

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

Uso:

InitializerGuard sizeInitializer; 

void PerformLayout() 
{ 
    Size size; 

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

    // ... 
} 

Pero si usted se encuentra el uso de este patrón muy a menudo esto podría indicar que una refactorización está en orden. Tal vez simplemente asignar valores predeterminados a algunas variables? ¿Por qué no se inicializan, de todos modos?

+1

o simplemente: 'Size size = HasRun()? parent.Size: _initSize; ' – leppie

+0

Esto es elegante y CLARO. Me gusta. Creo que voy a copiar esto. (¿Tal vez cambiaré el método HasRun a una propiedad en su lugar?) - Posiblemente podría refactorizar alguna parte de mi código, pero en muchos casos no tengo elección porque se usa en algunos eventos, y el código requiere algo de init en su primer fuego. – Larry

+1

@Laurent Properties no debe tener efectos secundarios. Por lo menos, esto arruina su depurador (si depura el código y agrega un reloj para esta variable, la propiedad se evalúa en momentos arbitrarios, lo que cambia su comportamiento). Entonces, si haces de esto una propiedad, rompes tu código de maneras "interesantes". ;-) –

1

Puede utilizar los tipos anulables y el operador coalescente nula para declarar una Size propiedad:

Size? _containerSize; 

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

entonces usted puede utilizar de esta manera:

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

Si el tipo que desea inicializar perezoso es un tipo de referencia, se vuelve aún más simple.

Otra opción es utilizar el tipo Lazy<T>. Esto se puede usar en escenarios de varios subprocesos donde el código anterior se puede romper:

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

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

Hay muchas maneras de lograr esto. Puede crear una máquina de estado compleja que realice su lógica (la más rápida) pero, en muchos casos, eso será excesivo. Alternativamente, puede hacer un seguimiento de un booleano que contiene el estado de su instancia tal como lo hace ahora. También puede optar por combinar ambas soluciones a una máquina de estado simple, con métodos como (moderatly rápida):

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