В этом конкретном примере вы можете сделать это:
using (var conn = new SqlConnection(...)) {
// Do work
}
То, что компилятор делает с этим утверждением, по существу:
SqlConnection conn;
try {
conn = new SqlConnection(...)
} finally {
conn.Dispose();
}
Или около того ... блок finally всегда выполняется, гарантируя, что блок using всегда вызывает Dispose.
Недостатком этого подхода является то, что вы не можете поймать исключение SqlException, которое может быть сгенерировано, поэтому в итоге вы делаете что-то вроде этого:
try {
using (var conn = new SqlConnection(...)) {
// Do work.
}
} catch (SqlException ex) {
}
Но скомпилированный код в конечном итоге представляет:
try {
SqlConnection conn;
try {
conn = new SqlConnection(...);
} finally {
conn.Dispose();
}
} catch (SqlException ex) {
}
Если честно, то, вероятно, это не будет иметь никакого значения для производительности, так как всякий раз, когда вы выбрасываете исключение, оно будет ударом по производительности. Это гарантирует, что Dispose всегда вызывается.