是否可以在 C# 中扩展 'using' 块?
Is it possible to extend the 'using' block in C#?
有没有一种方法可以扩展 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#?
一个using
块是shorthand一个try finally
块调用finally
中的Dispose
。它不能扩展到不止于此。你想要的是 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
});
您不能扩展 using
语句,但可以将其包装在一个方法中:
void DoStuff(Action action, ExceptionHandler log)
{
using(var connction = new SqlConnection(""))
{
try
{
action();
}
catch(Exception e)
{
log(e)
}
}
}
稍微退后一步,使用语法糖。
开始于:
using(var obj = factory_or_constructor())
{
// Do Stuff
}
是 shorthand 的常见模式
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;
}
}
这不是真的 "extending using" 但是如果 using
的目的是为通用模式提供简洁的语法,那么为稀有图案。
有没有一种方法可以扩展 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#?
一个using
块是shorthand一个try finally
块调用finally
中的Dispose
。它不能扩展到不止于此。你想要的是 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
});
您不能扩展 using
语句,但可以将其包装在一个方法中:
void DoStuff(Action action, ExceptionHandler log)
{
using(var connction = new SqlConnection(""))
{
try
{
action();
}
catch(Exception e)
{
log(e)
}
}
}
稍微退后一步,使用语法糖。
开始于:
using(var obj = factory_or_constructor())
{
// Do Stuff
}
是 shorthand 的常见模式
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;
}
}
这不是真的 "extending using" 但是如果 using
的目的是为通用模式提供简洁的语法,那么为稀有图案。