Je suis d'accord avec votre question. Le plus gros problème avec cet effet secondaire intentionnel est lorsque les développeurs ne le savent pas et suivent aveuglément la "meilleure pratique" d'entourer un StreamReader avec un using
. Mais il peut causer certains vraiment difficile de traquer les bugs quand il est sur la propriété d'un objet à long terme, le meilleur (pire?) Exemple, je l'ai vu est
using (var sr = new StreamReader(HttpContext.Current.Request.InputStream))
{
body = sr.ReadToEnd();
}
Le développeur avait aucune idée de l'InputStream est maintenant arrosé pour tout futur endroit qui s'attend à être là.
De toute évidence, une fois que vous connaissez les internes que vous connaissez pour éviter le using
et il suffit de lire et de réinitialiser la position. Mais je pensais qu'un principe de base de la conception de l'API était d'éviter les effets secondaires, en particulier de ne pas détruire les données sur lesquelles vous agissez. Rien d'inhérent à une classe censée être un "lecteur" ne devrait effacer les données lues une fois l'utilisation faite. La mise au rebut du lecteur devrait libérer toutes les références au Stream, ne pas effacer le flux lui-même. La seule chose que je peux penser est que le choix a dû être fait puisque le lecteur modifie l'autre état interne du Stream, comme la position du pointeur de recherche, qu'ils ont supposé si vous en enveloppez un autour, vous allez intentionnellement à être fait avec tout. D'un autre côté, comme dans votre exemple, si vous créez un flux, le flux lui-même sera dans un using
, mais si vous lisez un flux qui a été créé en dehors de votre méthode immédiate, il est présomptueux du code de effacer les données.
Ce que je fais et dis à nos développeurs à faire sur les instances de flux que le code de lecture ne crée pas explicitement est ...
// save position before reading
long position = theStream.Position;
theStream.Seek(0, SeekOrigin.Begin);
// DO NOT put this StreamReader in a using, StreamReader.Dispose() clears the stream
StreamReader sr = new StreamReader(theStream);
string content = sr.ReadToEnd();
theStream.Seek(position, SeekOrigin.Begin);
(désolé, j'ajouté cela comme une réponse, ne correspondraient pas à un commentaire, j'aimerais plus de discussion sur cette décision de conception du cadre)
Envisagez également d'utiliser System.IO.File.ReadAllText() dans des situations comme celles-ci. C'est plus simple. –
@ Dave Markle: vous avez raison. Je l'ai mis comme un court exemple. En fait, dans le code réel, les flux que je traite peuvent être très gros, donc le premier lecteur les lit ligne par ligne, ensuite, le flux est copié par octet dans un autre flux. –