iT邦幫忙

8

【C#】小知識 #5 : 為什麼要使用using

今天有新人問說:『為什麼connection要使用using直接呼叫Dispose不就好了?』,所以有了這篇文章,主要寫給Java轉C#或是不了解為何要使用using的工程師。

上面例子是不能直接呼叫Dispose的,之前有做過Java開發的工程師應該會習慣確保資源一定釋放會編寫try,finally,像是原本簡單的邏輯建立連線,釋放連線,需要編寫不少的代碼,以JDBC舉例:

try { 
    ..... 
    connection.setAutoCommit(false); 
    ..... 

    // 一連串SQL操作 
    connection.commit(); 
} catch(Exception) { 
    // 發生錯誤,撤消所有變更
    if(connection != null) {
        try {
            connection.rollback(); 
        catch(SQLException ex) {
            ex.printStackTrace();
        }
    }
}
finally {
    if(connection != null) {
        try {
            connection.close();
        }
        catch(SQLException e) {
            e.printStackTrace();
        }
    }
}

但是在C#我們可以簡單使用using達到同等效果,我們只需要編寫

SqlConnection cn = null;
using ( cn = new SqlConnection(this.Connection.ConnectionString))
{
	// 一連串SQL操作
}

為什麼這麼簡單?
因為編譯器幫我們做掉原本需要編寫的代碼,讓我們反編譯這段代碼來看一下,會發現其實底層還是try,finally,系統幫我們自動補齊代碼,是不是很人性化。

SqlConnection sqlConnection;
SqlConnection cn = sqlConnection = new SqlConnection(連線字串);
try
{
	// 一連串SQL操作
}
finally
{
	if (sqlConnection != null)
	{
		((IDisposable)sqlConnection).Dispose();
	}
}

2018-12-10.08.40.50-image.png


這時候系統先生出來說話了:『try,finally幫你做好了,我不可能知道你想要用甚麼邏輯釋放資源,麻煩你去實作Dispose方法,我會幫你呼叫它。』

使用using的類別需要實作IDisposable介面跟實作void Dispose()方法,告訴系統要照什麼邏輯釋放。像是string類別沒有實作IDisposable是無法使用using,會跳出CS1674 'string': type used in a using statement must be implicitly convertible to 'System.IDisposable'

2018-12-10.08.54.46-image.png

舉例:

class MyClass : IDisposable {
    // ...
    private bool disposed = false;

    public void Dispose() {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing) {
        if (!this.disposed) {
            if (disposing) {
                // 釋放資源邏輯
            }
            disposed = true;
        }
    }

    ~MyClass() {
        Dispose(false);
    }
}

補充:

感謝Cymon Dez補充,JDK7以後可以實作java.lang.AutoCloseable介面配合Try-with-resource statement達到相同目的。


4
fysh711426
iT邦研究生 4 級 ‧ 2018-12-10 09:18:40

我也喜歡用 using
使用 using 還有一個好處,可以確保物件不會在 Dispose 之後被使用

例如

using (var cn = new SqlConnection(this.Connection.ConnectionString))
{
    //做了一些事
}
cn.xxx <- 編譯錯誤

而不用 using 則可能會不小心呼叫到 Dispose 後的物件

var cn = new SqlConnection(this.Connection.ConnectionString)
//做了一些事
cn.Dispose();
//又做了一些事
cn.xxx <- 不小心呼叫了 Dispose 後的物件

不過怎麼我認識的工程師都不喜歡用 using
/images/emoticon/emoticon02.gif

暐翰 iT邦大師 2 級‧ 2018-12-10 09:56:28 檢舉

不過怎麼我認識的工程師都不喜歡用 using

對,會寫這篇原因也是新人問說『為什麼不直接呼叫Dispose還要使用using』

小魚 iT邦高手 1 級‧ 2018-12-10 13:42:24 檢舉

using比較方便啊,
我懶得去找怎麼釋放記憶體,
就直接using了 XD
其實就是懶...

暐翰 iT邦大師 2 級‧ 2018-12-11 08:15:09 檢舉

工程師有時候越懶反而好 XD

1
Luke
iT邦新手 3 級 ‧ 2018-12-10 10:32:40

/images/emoticon/emoticon06.gif

Java 轉C#
我都會用using ,很好用阿?

1
kgame
iT邦新手 4 級 ‧ 2018-12-11 13:45:16

using 超棒,有實作Dispose一定用using包

我要留言

立即登入留言