共用方式為


避免 Using 陳述式發生問題

這個範例說明當使用具型別用戶端時,為什麼不能使用 C# "using" 陳述式自動清除資源。 這個範例是以實作計算機服務的使用者入門範例為基礎。 在這個範例中,用戶端是主控台應用程式 (.exe),而服務則是由網際網路資訊服務 (IIS) 所裝載。

Aa355056.note(zh-tw,VS.100).gif注意:
此範例的安裝程序與建置指示位於本主題的結尾。

這個範例會說明兩個當 C# "using" 陳述式使用於具型別用戶端時發生的常見問題,並示範在例外狀況之後正確進行清除的程式碼。

C# "using" 陳述式會產生對 Dispose() 的呼叫。 這就跟呼叫 Close() 一樣,可能會在發生網路錯誤時擲回例外狀況。 因為對 Dispose() 的呼叫會隱含地發生在 "using" 區塊的右邊大括號,所以撰寫和閱讀程式碼的人可能都不會注意到這個例外狀況來源。 這代表應用程式錯誤的潛在來源。

要在 DemonstrateProblemUsingCanThrow 方法中說明的第一個問題,是右大括號會擲回例外狀況,而且右大括號之後的程式碼不會執行:

using (CalculatorClient client = new CalculatorClient())
{
    ...
} // <-- this line might throw
Console.WriteLine("Hope this code wasn't important, because it might not happen.");

即使在 using 區塊中沒有任何程式碼擲回例外狀況,或是已攔截到 using 區塊內的所有例外狀況,但 Console.Writeline 可能仍然不執行,這是因為右大括號所隱含的 Dispose() 呼叫可能擲回了例外狀況。

要在 DemonstrateProblemUsingCanThrowAndMask 方法中說明的第二個問題,則是右大括號的另一個會擲回例外狀況的隱含動作:

using (CalculatorClient client = new CalculatorClient())
{
    ...
    throw new ApplicationException("Hope this exception was not important, because "+
                                   "it might be masked by the Close exception.");
} // <-- this line might throw an exception.

因為 Dispose() 會在 "finally" 區塊內發生,如果 Dispose() 失敗,則永遠無法在 using 區塊之外見到 ApplicationException。 如果區塊外面的程式碼必須知道 ApplicationException 何時發生,"using" 建構便可能因為遮罩了這個例外狀況而造成問題。

最後,範例會在 DemonstrateCleanupWithExceptions 中示範如何於例外狀況發生時正確清除。 這段程式碼會使用 try/catch 區塊,報告錯誤並呼叫 Abort。 如需快取用戶端呼叫所造成之例外狀況的詳細資訊,請參閱預期的例外狀況範例。

try
{
    ...
    client.Close();
}
catch (CommunicationException e)
{
    ...
    client.Abort();
}
catch (TimeoutException e)
{
    ...
    client.Abort();
}
catch (Exception e)
{
    ...
    client.Abort();
    throw;
}
Aa355056.note(zh-tw,VS.100).gif注意:
using 陳述式和 ServiceHost:許多自我裝載應用程式的工作最多不過是裝載服務,而 ServiceHost.Close 則很少會擲回例外狀況,因此這類應用程式可以安全地搭配 ServiceHost 使用 using 陳述式。 但是要注意,ServiceHost.Close 可能擲回 CommunicationException,因此,如果應用程式會在關閉 ServiceHost 之後繼續執行,您應該避免使用 using 陳述式,而要遵循前述的模式。

當您執行範例時,作業回應和例外狀況會顯示在用戶端主控台視窗中。

用戶端處理序將執行三個案例,其中每一個都會嘗試呼叫 Divide。 第一個案例示範因 Dispose() 發生例外狀況而略過程式碼的情況。 第二個案例示範因 Dispose() 發生例外狀況而遮罩了重要例外狀況的情況。 第三個案例則示範進行正確清除。

從用戶端處理序產生的預期輸出如下:

=
= Demonstrating problem:  closing brace of using statement can throw.
=
Got System.ServiceModel.CommunicationException from Divide.
Got System.ServiceModel.Security.MessageSecurityException
=
= Demonstrating problem:  closing brace of using statement can mask other Exceptions.
=
Got System.ServiceModel.CommunicationException from Divide.
Got System.ServiceModel.Security.MessageSecurityException
=
= Demonstrating cleanup with Exceptions.
=
Calling client.Add(0.0, 0.0);
        client.Add(0.0, 0.0); returned 0
Calling client.Divide(0.0, 0.0);
Got System.ServiceModel.CommunicationException from Divide.

Press <ENTER> to terminate client.

若要設定、建置及執行範例

  1. 請確定您已執行 Windows Communication Foundation 範例的單次安裝程序

  2. 若要建置方案的 C# 或 Visual Basic .NET 版本,請遵循建置 Windows Communication Foundation 範例中的指示。

  3. 若要在單一或跨機器的組態中執行本範例,請遵循Running the Windows Communication Foundation Samples中的指示進行。

Aa355056.Important(zh-tw,VS.100).gif 注意:
這些範例可能已安裝在您的電腦上。 請先檢查下列 (預設) 目錄,然後再繼續。

<InstallDrive>:\WF_WCF_Samples

如果此目錄不存在,請移至用於 .NET Framework 4 的 Windows Communication Foundation (WCF) 與 Windows Workflow Foundation (WF) 範例 (英文),以下載所有 Windows Communication Foundation (WCF) 和 WF 範例。 此範例位於下列目錄。

<InstallDrive>:\WF_WCF_Samples\WCF\Basic\Client\UsingUsing