Editar: dos opciones que se muestran a continuación.¿Cuál es la mejor manera de volver IDisposables construidos de manera segura?
Si solo tiene usando la funcionalidad que proporciona un IDisposable, la cláusula using
acertadamente funciona bien. Si está envolviendo un IDisposable
en un objeto, el objeto que lo contiene debe ser IDisposable
y debe implementar el patrón apropiado (ya sea una clase sellada IDisposable
, o la más desordenada pero standard virtual
pattern).
Pero a veces un método de fábrica ayudante es bueno para la limpieza. Si devuelve un IDisposable
directamente después de la construcción, que está bien, pero si primero se construye y luego modificarlo o no ejecutar el código que puede lanzar una excepción antes de regresar, es necesario llamar a seguridad .Dispose()
- pero solamente si había un error.
Por ejemplo, el código inseguro podría tener este aspecto ...
DbCommand CreateCommandUnsafely(string commandText)
{
var newCommand = connection.CreateCommand();
newCommand.CommandText = commandText; //what if this throws?
return newCommand;
}
Soluciones dos variantes seguras sigue ...
DbCommand CreateCommandSafelyA(string commandText)
{
DbCommand newCommand = null;
bool success = false;
try {
newCommand = connection.CreateCommand();
newCommand.CommandText = commandText; //if this throws...
success=true;
return newCommand;
} finally{
if (!success && newCommand != null)
newCommand.Dispose(); //...we'll clean up here.
}
}
DbCommand CreateCommandSafelyB(string commandText)
{
DbCommand newCommand = null;
try {
newCommand = connection.CreateCommand();
newCommand.CommandText = commandText; //if this throws...
return newCommand;
} catch {
if (newCommand != null)
newCommand.Dispose(); //...we'll clean up here.
throw;
}
}
Segura variante A es sólo una línea más larga , pero parece ser el enfoque idiomático. No parece que haya ninguna solución muy concisos, aunque algunos carteles dan a continuación algunas opciones lambda-que extraen mediante el encapsulado de esta lógica.
La hinchazón de código con cualquiera de los métodos anteriormente seguras sigue siendo, y es especialmente agravante con código que inicialmente parecía ...
return new MyDisposableThing {
OptionA = "X",
OptionB = B.Blabla,
Values = src.Values.Where(priority => priority > 1.0),
};
El código anterior se escribe de forma segura es un poco más largo y menos legible porque ya no puede usar con seguridad la sintaxis del organizador acortado.
Parece el código que veo en otra parte. ¿Sabes por qué es esto preferible? –
La captura de excepciones arbitrarias (como las otras respuestas parecen abogar) causa una variedad de problemas en circunstancias especiales, y debe evitarse siempre que sea posible. Al colocar la eliminación dentro de una declaración 'finally', el patrón estándar evita capturar excepciones, y (cuando la creación del objeto falla) imita el comportamiento de la instrucción' using' nominal. –