Prevenzione dei problemi con l'istruzione UsingAvoiding Problems with the Using Statement

In questo esempio si consiglia di non utilizzare l'istruzione "using" di C# per pulire automaticamente le risorse quando si utilizza un client tipizzato.This sample demonstrates how you should not use the C# "using" statement to automatically clean up resources when using a typed client. Questo esempio è basato sul Introduzione che implementa un servizio di calcolatrice.This sample is based on the Getting Started that implements a calculator service. In questo esempio, il client è un'applicazione console (.exe) e il servizio è ospitato da Internet Information Services (IIS).In this sample, the client is a console application (.exe) and the service is hosted by Internet Information Services (IIS).

Nota

La procedura di installazione e le istruzioni di compilazione per questo esempio si trovano alla fine di questo argomento.The setup procedure and build instructions for this sample are located at the end of this topic.

In questo esempio vengono illustrati due dei problemi comuni che si verificano in caso di utilizzo dell'istruzione "using" di C# con i client tipizzati e il codice che pulisce correttamente le eccezioni.This sample shows two of the common problems that occur when using the C# "using" statement with typed clients, as well as code that correctly cleans up after exceptions.

L'istruzione "using" di C# genera una chiamata a Dispose().The C# "using" statement results in a call to Dispose(). Questo corrisponde a Close(), che può generare eccezioni quando si verifica un errore di rete.This is the same as Close(), which may throw exceptions when a network error occurs. Poiché la chiamata a Dispose() si verifica implicitamente alla parentesi graffa di chiusura del blocco "using", è probabile che l'origine delle eccezioni non venga rilevata da chi scrive il codice e da chi lo legge.Because the call to Dispose() happens implicitly at the closing brace of the "using" block, this source of exceptions is likely to go unnoticed both by people writing the code and reading the code. Questa situazione può causare errori dell'applicazione.This represents a potential source of application errors.

Il primo problema, illustrato nel metodo DemonstrateProblemUsingCanThrow è che la parentesi graffa di chiusura genera un'eccezione e il codice dopo che la parentesi graffa di chiusura non viene eseguito:The first problem, illustrated in the DemonstrateProblemUsingCanThrow method, is that the closing brace throws an exception and the code after the closing brace does not execute:

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

Anche se non vengono generate eccezioni nel blocco "using" o se tutte le eccezioni all'interno del blocco "using" vengono rilevate, Console.Writeline potrebbe non verificarsi visto che la chiamata Dispose() implicita potrebbe generare un'eccezione alla parentesi graffa di chiusura.Even if nothing inside the using block throws an exception or all exceptions inside the using block are caught, the Console.Writeline might not happen because the implicit Dispose() call at the closing brace might throw an exception.

Il secondo problema, illustrato nel metodo DemonstrateProblemUsingCanThrowAndMask deriva da un'altra implicazione della parentesi graffa di chiusura che genera un'eccezione:The second problem, illustrated in the DemonstrateProblemUsingCanThrowAndMask method, is another implication of the closing brace throwing an exception:

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.  

Poiché Dispose() si verifica in un blocco "finally", ApplicationException non viene mai visualizzato al di fuori del blocco "using" se si verifica un errore in Dispose().Because the Dispose() occurs inside a "finally" block, the ApplicationException is never seen outside the using block if the Dispose() fails. Se il codice esterno deve essere in grado di rilevare quando si verifica ApplicationException, si potrebbero verificare problemi se il costrutto "using" maschera questa eccezione.If the code outside must know about when the ApplicationException occurs, the "using" construct may cause problems by masking this exception.

Nell'esempio viene infine illustrato come pulire correttamente le eccezioni che si verificano in DemonstrateCleanupWithExceptions.Finally, the sample demonstrates how to clean up correctly when exceptions occur in DemonstrateCleanupWithExceptions. Questa operazione utilizza un blocco try/catch per segnalare gli errori e chiamare Abort.This uses a try/catch block to report errors and call Abort. Vedere il previsto eccezioni sample per ulteriori informazioni sull'intercettazione di eccezioni da chiamate del client.See the Expected Exceptions sample for more details about catching exceptions from client calls.

try  
{  
    ...  
    client.Close();  
}  
catch (CommunicationException e)  
{  
    ...  
    client.Abort();  
}  
catch (TimeoutException e)  
{  
    ...  
    client.Abort();  
}  
catch (Exception e)  
{  
    ...  
    client.Abort();  
    throw;  
}  

Nota

Istruzione using e ServiceHost: molte applicazioni indipendenti non fanno altro che ospitare un servizio e ServiceHost.Close raramente genera un'eccezione, pertanto tali applicazioni possono utilizzare in modo sicuro l'istruzione using con ServiceHost.The using statement and ServiceHost: Many self-hosting applications do little more than host a service, and ServiceHost.Close rarely throws an exception, so such applications can safely use the using statement with ServiceHost. Tuttavia, è consigliabile prendere in considerazione che ServiceHost.Close può generare un'eccezione CommunicationException, pertanto se l'applicazione è ancora in esecuzione dopo avere chiuso ServiceHost, è necessario evitare di utilizzare l'istruzione using e seguire il modello fornito in precedenza.However, be aware that ServiceHost.Close can throw a CommunicationException, so if your application continues after closing the ServiceHost, you should avoid the using statement and follow the pattern previously given.

Quando si esegue l'esempio, le risposte e le eccezioni dell'operazione vengono visualizzate nella finestra della console client.When you run the sample, the operation responses and exceptions are displayed in the client console window.

Il processo client esegue tre scenari, ognuno dei quali tenta di chiamare Divide.The client process runs three scenarios, each of which attempts to call Divide. Nel primo scenario viene descritto il codice ignorato a causa di un'eccezione da Dispose().The first scenario demonstrates code being skipped because of an exception from Dispose(). Nel secondo scenario viene illustrata un'eccezione importante mascherata a causa di un'eccezione da Dispose().The second scenario demonstrates an important exception being masked because of an exception from Dispose(). Nel terzo scenario viene illustrato come eseguire correttamente la pulizia.The third scenario demonstrates correct clean up.

L'output previsto dal processo client è:The expected output from the client process is:

=  
= 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.  

Per impostare, compilare ed eseguire l'esempioTo set up, build, and run the sample

  1. Assicurarsi di avere eseguito la procedura di installazione singola per gli esempi di Windows Communication Foundation.Ensure that you have performed the One-Time Setup Procedure for the Windows Communication Foundation Samples.

  2. Per compilare l'edizione in C# o Visual Basic .NET della soluzione, seguire le istruzioni in Building the Windows Communication Foundation Samples.To build the C# or Visual Basic .NET edition of the solution, follow the instructions in Building the Windows Communication Foundation Samples.

  3. Per eseguire l'esempio in una configurazione singola o tra computer, seguire le istruzioni in esegue gli esempi di Windows Communication Foundation.To run the sample in a single- or cross-machine configuration, follow the instructions in Running the Windows Communication Foundation Samples.

Importante

È possibile che gli esempi siano già installati nel computer.The samples may already be installed on your machine. Verificare la directory seguente (impostazione predefinita) prima di continuare.Check for the following (default) directory before continuing.

<InstallDrive>:\WF_WCF_Samples

Se questa directory non esiste, andare al Windows Communication Foundation (WCF) e gli esempi di Windows Workflow Foundation (WF) per .NET Framework 4 per scaricare tutti i Windows Communication Foundation (WCF) e WFWF esempi.If this directory does not exist, go to Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4 to download all Windows Communication Foundation (WCF) and WFWF samples. Questo esempio si trova nella directory seguente.This sample is located in the following directory.

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

Vedere ancheSee Also