Réponses:
Comme plusieurs autres l'ont souligné en général, ce n'est pas un problème.
Le seul cas où cela vous posera des problèmes est si vous revenez au milieu d'une instruction using et que vous retournez également la variable in using. Mais là encore, cela vous causerait également des problèmes même si vous ne retourniez pas et gardiez simplement une référence à une variable.
using ( var x = new Something() ) {
// not a good idea
return x;
}
Tout aussi mauvais
Something y;
using ( var x = new Something() ) {
y = x;
}
return
instruction rend la fin du using
bloc inaccessible par tous les chemins de code. La fin du using
bloc doit être exécutée afin que l'objet puisse être supprimé si nécessaire.
C'est parfaitement bien.
Vous pensez apparemment que
using (IDisposable disposable = GetSomeDisposable())
{
//.....
//......
return Stg();
}
se traduit aveuglément en:
IDisposable disposable = GetSomeDisposable()
//.....
//......
return Stg();
disposable.Dispose();
Ce qui, certes, serait un problème, et rendrait la using
déclaration plutôt inutile - c'est pourquoi ce n'est pas ce qu'il fait.
Le compilateur s'assure que l'objet est supprimé avant que le contrôle ne quitte le bloc, quelle que soit la façon dont il quitte le bloc.
C'est très bien - pas de problème du tout. Pourquoi croyez-vous que c'est mal?
Une instruction using n'est que du sucre syntaxique pour un bloc try / finally, et comme le dit Grzenio, il est également possible de revenir d'un bloc try.
L'expression de retour sera évaluée, puis le bloc finally sera exécuté, puis la méthode reviendra.
C'est tout à fait acceptable. Une utilisation instruction garantit que l'objet IDisposable sera supprimé quoi qu'il arrive.
Depuis MSDN :
L'instruction using garantit que Dispose est appelé même si une exception se produit pendant que vous appelez des méthodes sur l'objet. Vous pouvez obtenir le même résultat en plaçant l'objet dans un bloc try, puis en appelant Dispose dans un bloc finally; en fait, c'est ainsi que l'instruction using est traduite par le compilateur.
Le code ci-dessous montre comment using
fonctionne:
private class TestClass : IDisposable
{
private readonly string id;
public TestClass(string id)
{
Console.WriteLine("'{0}' is created.", id);
this.id = id;
}
public void Dispose()
{
Console.WriteLine("'{0}' is disposed.", id);
}
public override string ToString()
{
return id;
}
}
private static TestClass TestUsingClose()
{
using (var t1 = new TestClass("t1"))
{
using (var t2 = new TestClass("t2"))
{
using (var t3 = new TestClass("t3"))
{
return new TestClass(String.Format("Created from {0}, {1}, {2}", t1, t2, t3));
}
}
}
}
[TestMethod]
public void Test()
{
Assert.AreEqual("Created from t1, t2, t3", TestUsingClose().ToString());
}
Production:
't1' est créé.
't2' est créé.
't3' est créé.
'Créé à partir de t1, t2, t3' est créé.
«t3» est supprimé.
't2' est supprimé.
«t1» est supprimé.
Les éliminés sont appelés après l'instruction return mais avant la sortie de la fonction.
Ce n'est peut-être pas vrai à 100% que c'est acceptable ...
S'il vous arrive d'imbriquer des utilisations et de revenir de l'intérieur d'une imbriquée, cela peut ne pas être sûr.
Prenez ceci comme exemple:
using (var memoryStream = new MemoryStream())
{
using (var textwriter = new StreamWriter(memoryStream))
{
using (var csv = new CsvWriter(textwriter))
{
//..write some stuff to the stream using the CsvWriter
return memoryStream.ToArray();
}
}
}
Je passais dans un DataTable pour être sorti en csv. Avec le retour au milieu, il écrivait toutes les lignes dans le flux, mais le csv en sortie manquait toujours une ligne (ou plusieurs, selon la taille du tampon). Cela m'a dit que quelque chose n'était pas fermé correctement.
La bonne façon est de vous assurer que toutes les utilisations précédentes sont éliminées correctement:
using (var memoryStream = new MemoryStream())
{
using (var textwriter = new StreamWriter(memoryStream))
{
using (var csv = new CsvWriter(textwriter))
{
//..write some stuff to the stream using the CsvWriter
}
}
return memoryStream.ToArray();
}