2010-12-08 19 views
24

Tengo el siguiente código pero es incómodo. ¿Cómo podría estructurarlo mejor? ¿Tengo que hacer que mi clase consumidora implemente IDisposable y condicionalmente construir la clase de acceso a la red y disponer de ella cuando haya terminado?C# condicional que usa instrucción de bloque

protected void ValidateExportDirectoryExists() 
    { 
     if (useNetworkAccess) 
     { 
      using (new Core.NetworkAccess(username, password, domain)) 
      { 
       CheckExportDirectoryExists(); 
      } 
     } 
     else 
     { 
      CheckExportDirectoryExists(); 
     } 
    } 
+4

¿Por qué es incómodo? Me parece bastante directo. –

+2

@Joel Etherton: Probablemente debido a la repetición de esa llamada 'CheckExportDirectoryExists()'. – BoltClock

+7

Si ese es el bit más incómodo de tu código, estás muy bien. – Nate

Respuesta

50

Una opción, que es algo desagradable, pero funcionaría, basado en el hecho de que el compilador de C# llama Dispose sólo si el recurso no es nulo:

protected void ValidateExportDirectoryExists() 
{ 
    using (useNetworkAccess 
       ? new Core.NetworkAccess(username, password, domain) 
       : null) 
    { 
     CheckExportDirectoryExists(); 
    } 
} 

Otra alternativa sería escribir un método estático que volvió ya sea nulo o un NetworkAccess:

private Core.NetworkAccess CreateNetworkAccessIfNecessary() 
{ 
    return useNetworkAccess 
     ? new Core.NetworkAccess(username, password, domain)) : null; 
} 

Entonces:

protected void ValidateExportDirectoryExists() 
{ 
    using (CreateNetworkAccessIfNecessary()) 
    { 
     CheckExportDirectoryExists(); 
    } 
} 

De nuevo, todavía no estoy seguro de que no prefiera el original ... realmente depende de la frecuencia con la que necesite este patrón.

+1

Tienes la lógica al revés. Swap 'null' y la expresión' new'. – cdhowie

+0

Original es más bonito, pero +1 de todos modos :) –

+0

@cdhowie: Reparado, gracias :) –

0

usando scope solo eliminará un objeto si la clase implementa la interfaz IDisposible así que sí necesita implementar el método de eliminación.

0

Supongo que es realmente una cuestión de cosméticos si el código es tan simple como eso.

Puedo imaginar cómo podría mirar hacia otro lado, y mi voto será para esta versión que tiene ahora.

0

Todo lo que se incluye en la instrucción using tendrá su IDispoable.Dispose llamado según lo dictado por la interfaz IDisposable. Como se ve en MSDN para using ...

Proporciona una sintaxis conveniente que asegura el correcto uso de IDisposable objetos.

Por lo tanto si se pone un tipo personalizado dentro de la instrucción using debe limpiar sus recursos de forma apropiada a través de la interfaz IDisposable.

7

Si repite este patrón en muchos métodos que puede romper el patrón

protected void OptionalNetworkCall(Action action) 
{ 
    if (useNetworkAccess) 
    { 
     using (new Core.NetworkAccess(username, password, domain)) 
     { 
      action(); 
     } 
    } 
    else 
    { 
     action(); 
    } 
} 

protected void ValidateExportDirectoryExists() 
{ 
    OptionalNetworkCall(CheckExportDirectoryExists); 
} 
0

Al tener su clase implemente IDisposable, el método dispose se llama sólo cuando se utiliza el "uso" comunicado. De lo contrario, tiene que llamar explícitamente a disponer.

Normalmente, IDisposable se implementa mediante objetos que administran el consumo de memoria fuera del recolector de elementos no usados ​​(como, por ejemplo, usar código no administrado). Proporciona una forma de limpiar cualquier memoria consumida.

Mientras su clase de NetworkAccess implemente IDisposable, se llamará al método de eliminación tan pronto como se complete el alcance de la instrucción de uso. Si se trata de código administrado, entonces no hay necesidad de deshacerse de él. Solo deja que el recolector de basura haga su trabajo.

1

No sé si es "mejor", pero podría usar el patrón de objeto nulo y tener un objeto de acceso a red desechable "nulo".Algo como esto:

protected void ValidateExportDirectoryExists()  
{ 
    using (GetNetworkAccess(username, password, domain)) 
    {     
    CheckExportDirectoryExists(); 
    } 
} 

protected IDisposable GetNetworkAccess(string username, string password, string domain) 
{ 
    return useNetworkAccess ? new Core.NetworkAccess(username, password, domain) : new NullNetworkAccess(username, password, domain); 
} 

internal class NullNetworkAccess : IDisposable 
{ 
    internal NullNetworkAccess(string username, string password, string domain) 
    { 
    } 

    public void Dispose() 
    { 
    } 
} 

Esto es probablemente demasiado lindo para su propio bien.

[EDIT] Acabo de ver en la respuesta de Jon que null se puede utilizar en una instrucción de uso. ¡No tenía ni idea!

1
protected void ValidateExportDirectoryExists() 
{ 
     var access = useNetworkAccess 
      ? new Core.NetworkAccess(username, password, domain) 
      : null; 

     using (access) 
     { 
      CheckExportDirectoryExists(); 
     } 
} 
0

Use su propio try/finally, que realiza una lógica similar a la 'usando', pero sólo lo hace el disponer si se ha establecido useNetworkAccess. Tenga en cuenta que si useNetworkAccess puede verse afectado por otros subprocesos, debe copiar su valor y usar esa copia para crear el recurso y eliminarlo.

4

La instrucción using es un atajo para evitar bloques "finalmente" y solo debe utilizarse cuando hace que el código sea más fácil de seguir. En tu caso, escribiría el siguiente código. Puede que no sea tan breve como algunas de las otras versiones, pero es mucho más sencillo.

protected void ValidateExportDirectoryExists() 
{ 
    Core.NetworkAccess access = useNetworkAccess ? new Core.NetworkAccess(username, password, domain) : null;  

    try 
    { 
     CheckExportDirectoryExists() 
    } 
    finally 
    { 
     if (access != null) 
     { 
      access.Dispose(); 
     } 
    } 
} 
+0

Estoy de acuerdo, creo que esto es más revelador de intenciones que el enunciado de uso, simplemente porque es inmediatamente obvio que el acceso es opcional, debido a esa comprobación nula en la declaración final, donde como una declaración de uso ofusca un poco la intención. – Bittercoder

+0

creo que esta es la mejor respuesta solo porque hace el mejor trabajo de mostrar intención mientras se hace lo que se necesita sin ser "inteligente" de ninguna manera. este sería el idiomático C# way imo. –