是否有办法在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#?
答案 0 :(得分:35)
using
阻止是try finally
阻止Dispose
中finally
调用的简写。它不能扩展为更多的东西。你想要的是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
的要点是对于一个共同的模式有一个简洁的语法,那么它对于一个稀有模式的简洁语法并不是很有用。