objeto - ¿Es posible extender el bloque ''utilizando'' en C#?
using instruction c# (3)
No puede extender la instrucción using
pero puede envolverla en un método:
void DoStuff(Action action, ExceptionHandler log)
{
using(var connction = new SqlConnection(""))
{
try
{
action();
}
catch(Exception e)
{
log(e)
}
}
}
¿Hay una manera de extender el bloque de using
en C # de tal manera que tome a un delegado como segundo parámetro junto con un objeto IDisponible y se ejecute cada vez que se lanza una excepción dentro de ese bloque de using
?
Imagina que tenemos un delegado, algo como esto:
public delegate void ExceptionHandler(Exception ex);
Y supongamos que tengo un método que coincide con ese delegado, algo como esto:
public void Log(Exception ex)
{
// Some logging stuff goes here
}
Y quiero lograr algo como esto:
using(SqlConnection connection = new SqlConnection(""), Log)
{
}
¿Hay una manera de extender C # de tal manera?
Solo retrocede un poco con el azúcar sintáctico.
Ya que:
using(var obj = factory_or_constructor())
{
// Do Stuff
}
Es taquigrafía para el patrón común.
obj = factory_or_constructor();
try
{
// Do Stuff
}
finally
{
((IDisposable)obj)?.Dispose();
}
Entonces podrías simplemente cambiarlo a:
try
{
// Do Stuff
}
catch(Exception ex)
{
Log(ex);
throw;
}
finally
{
((IDisposable)obj)?.Dispose();
}
Pero entonces realmente no ofrece mucho más sobre lo más simple y claro.
using(var obj = factory_or_constructor())
{
try
{
// Do Stuff
}
catch(Exception ex)
{
Log(ex);
throw;
}
}
No es realmente "extender el uso", pero si el punto de using
es tener una sintaxis concisa para un patrón común, no es tan útil como una sintaxis concisa para un patrón raro.
Un bloque de using
es una abreviatura para un bloque de try finally
con una llamada a Dispose
en el finally
. No se puede extender para ser algo más que eso. Lo que quieres es la funcionalidad de una try catch finally
, así que ¿por qué no usar exactamente eso?
SqlConnection connection = new SqlConnection("");
try {
}
catch (Exception exc) {
Log(exc);
}
finally {
connection.Dispose();
}
Esto viene con todas las ventajas de una try catch finally
, por ejemplo, captura múltiples tipos de excepción y filtros de excepción C # 6.0. Considera esto:
SqlConnection connection = new SqlConnection("");
try {
}
catch (SqlException exc) when (exc.Number > 0) {
//Handle SQL error
}
catch (Exception exc) {
Log(exc);
}
finally {
connection.Dispose();
}
Si desea reutilizar los bloques de try catch finally
estandarizados, puede usar delegados:
static class ErrorHandler {
public static ExecuteWithErrorHandling<T>(Func<T> createObject,
Action<Exception> exceptionHandler, Action<T> operation) where T : IDisposable {
T disposable = createObject();
try {
operation(disposable);
}
catch (Exception exc) {
exceptionHandler(exc);
}
finally {
disposable.Dispose();
}
}
}
Que puedes llamar como:
ErrorHandler.ExecuteWithErrorHandling(() => new SqlConnection(""), Log, connection => {
//Use connection here
});