2010-10-19 19 views
6

Si vous êtes venu dans un code C# comme celui-ci avec les déclarations imbriquées en utilisant/ressources:.NET - Remplaçant imbriquées en utilisant des énoncés unique à l'aide déclaration

using (var response = (HttpWebResponse)request.GetResponse()) 
{ 
    using (var responseStream = response.GetResponseStream()) 
    { 
     using (var reader = new BinaryReader(responseStream)) 
     { 
      // do something with reader 
     } 
    } 
} 

Est-il sûr de le remplacer par quelque chose comme ça? L'exemple ci-dessus est juste un exemple de ressources jetables imbriquées, alors pardonnez-moi si ce n'est pas exactement l'utilisation correcte. Je suis curieux de savoir si vous disposez de la ressource la plus externe (le BinaryReader dans ce cas), si elle disposera récursivement ses enfants pour vous, ou si vous devez explicitement disposer chaque "couche" avec des instructions using séparées? Par exemple. Si vous disposez du BinaryReader, est-il censé disposer le flux de réponse, qui à son tour dispose de la réponse? En pensant à cette dernière phrase, je pense que vous avez réellement besoin des instructions using using séparées, parce qu'il n'y a aucun moyen de garantir qu'un objet wrapper disposerait de l'objet interne. Est-ce correct?

Répondre

12

Vous avez besoin des instructions using séparées.

Dans votre deuxième exemple, seul le BinaryReader sera mis au rebut, pas les objets utilisés pour le construire. Pour voir pourquoi, regardez ce que fait réellement le using statement. Il prend votre deuxième code, et fait quelque chose d'équivalent à:

{ 
    var reader = new BinaryReader(((HttpWebResponse)request.GetResponse()).GetResponseStream()); 
    try 
    { 
     // do something with reader 
    } 
    finally 
    { 
     if (reader != null) 
      ((IDisposable)reader).Dispose(); 
    } 
} 

Comme vous pouvez le voir, sur le Response ou ResponseStream il n'y aurait jamais un appel Dispose().

using (var response = (HttpWebResponse)request.GetResponse()) 
using (var responseStream = response.GetResponseStream()) 
using (var reader = new BinaryReader(responseStream)) 
{ 
    // do something with reader 
} 
+0

Vous en avez besoin, mais je ne pense pas qu'ils doivent être imbriqués. Je pense qu'ils peuvent simplement être empilés les uns sur les autres. –

+0

@Matt: Oui, mais ils doivent tous les trois exister. –

+0

'BinaryReader.Close' ferme le flux sous-jacent. Et puisque 'Stream.Close' finit par appeler' Stream.Dispose', il n'est pas nécessaire de fermer le flux après avoir fermé le lecteur. Voir http://msdn.microsoft.com/en-us/library/system.net.httpwebresponse.aspx et http://msdn.microsoft.com/en-us/library/system.io.stream.close.aspx . –

13

Vous devez juste empiler vos déclarations à l'aide que vous recherchez, il a l'effet désiré

using (var response = (HttpWebResponse)request.GetResponse()) 
using (var responseStream = response.GetResponseStream()) 
using (var reader = new BinaryReader(responseStream)) 
{ 
    // do something with reader 
} 

Si le lecteur dispose du flux est vraiment une fonction du lecteur, pas l'utilisation. Si je me souviens bien, c'est souvent le comportement des lecteurs - ils prennent la propriété du flux et s'en débarrassent lorsque le lecteur est lui-même fermé. Mais le formulaire que j'ai fourni ci-dessus devrait être bon.

+0

Il s'agit essentiellement du même code avec un formatage différent (en supprimant simplement les accolades). –

+0

Comment cela améliore-t-il les choses, c'est-à-dire ce que l'OP avait juste moins les accolades qui étaient optionnelles pour les deux premières instructions 'using '. – slugster

+0

Oui, c'est la même chose, mais par rapport à ce que l'auteur voulait remplacer par l'original, c'est beaucoup plus facile à lire et à maintenir –

3

FWIW, voici une autre façon d'écrire votre exemple original qui peut satisfaire une grande consternation sur l'imbrication:: -

1

Selon la documentation, BinaryReader.Close fermera le flux sous-jacent. En outre, selon la documentation de HttpWebResponse, vous devez soit fermer le flux sous-jacent, soit disposer la réponse. http://msdn.microsoft.com/en-us/library/system.net.httpwebresponse.aspx

Donc le deuxième exemple que vous avez fourni fonctionnerait.

+0

Merci pour la réponse ... Je me doutais qu'il y avait d'autres possibilités. Je suppose qu'en cas de doute, il vaut mieux tout simplement Fermer ou Tout jeter, à moins de savoir ce que chaque type fait. –

0

J'ai posté ceci ailleurs, mais séparer vos déclarations par des virgules semble traiter chaque déclaration comme une nouvelle déclaration et en disposer.

using (IType1 a = new Type1(), b = new Type1()){}

Cela signifie cependant vos objets doivent être du même type.Vous pouvez les appeler comme

using (IDisposable a = new Type1(), b = new Type2()){}

Mais, il vous suffit alors bien sûr l'accès aux méthodes IDisposable, sans jeter l'objet, ce qui est un peu stupide. Ainsi, au lieu, je crois que vous pouvez utiliser

using (var a = new Type1(), b = new Type2()){}

Cela semble vous donner les références d'objets typés correctement vous permettant d'accéder à la méthode appropriée du type attribué, et dispose des deux objets créés. Si quelqu'un sait pourquoi je n'ai pas raison, s'il vous plaît faites le moi savoir parce que cela semble fonctionner pour moi? (Je sais que cette question est vraiment ancienne, mais c'est tout ce que j'ai pu trouver en cherchant cette réponse moi-même)