是否可以延长使用'阻止C#?

时间:2017-02-28 13:35:57

标签: c# .net using-statement

是否有办法在C#中扩展using块,以便将委托作为第二个参数与IDisposable对象一起使用,并在每次在using内抛出异常时执行方框?

想象一下,我们有一个代表,就像这样:

public delegate void ExceptionHandler(Exception ex);

假设我有一个匹配该委托的方法,如下所示:

public void Log(Exception ex)
{
  // Some logging stuff goes here
}

我想完成这样的事情:

using(SqlConnection connection = new SqlConnection(""), Log)
{

}

有没有办法以这种方式扩展C#?

3 个答案:

答案 0 :(得分:35)

using阻止是try finally阻止Disposefinally调用的简写。它不能扩展为更多的东西。你想要的是try catch finally的功能,所以为什么不使用那个:

SqlConnection connection = new SqlConnection("");
try {

}
catch (Exception exc) {
    Log(exc);
}
finally {
    connection.Dispose();
}

这带来了try catch finally的所有优点,例如捕获多个异常类型和C#6.0异常过滤器。考虑一下:

SqlConnection connection = new SqlConnection("");
try {

}
catch (SqlException exc) when (exc.Number > 0) {
    //Handle SQL error
}
catch (Exception exc) {
    Log(exc);
}
finally {
    connection.Dispose();
}

如果您想重复使用标准try catch finally块,可以使用委托:

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();
        }
    }
}

你可以这样称呼:

ErrorHandler.ExecuteWithErrorHandling(() => new SqlConnection(""), Log, connection => {
    //Use connection here
});

答案 1 :(得分:14)

您无法扩展using语句,但可以将其包装在方法中:

void DoStuff(Action action, ExceptionHandler log)
{
    using(var connction = new SqlConnection(""))
    {
        try
        {
            action();
        }
        catch(Exception e)
        {
            log(e)
        }
    }
}

答案 2 :(得分:4)

请稍微退一步说法。

自:

using(var obj = factory_or_constructor())
{
  // Do Stuff
}

是常见模式的简写

obj = factory_or_constructor();
try
{
  // Do Stuff
}
finally
{
  ((IDisposable)obj)?.Dispose();
}

然后您可以将其更改为:

try
{
  // Do Stuff
}
catch(Exception ex)
{
  Log(ex);
  throw;
}
finally
{
  ((IDisposable)obj)?.Dispose();
}

但是,它并没有提供更多更简单和更清晰的东西。

using(var obj = factory_or_constructor())
{
  try
  {
    // Do Stuff
  }
  catch(Exception ex)
  {
    Log(ex);
    throw;
  }
}

它不是真的&#34;使用&#34;但是如果using的要点是对于一个共同的模式有一个简洁的语法,那么它对于一个稀有模式的简洁语法并不是很有用。