Mon problème fondamental est que lorsque vous using
appelez Dispose
a StreamWriter
, il élimine également le BaseStream
(même problème avec Close
).
J'ai une solution de contournement pour cela, mais comme vous pouvez le voir, cela implique de copier le flux. Existe-t-il un moyen de le faire sans copier le flux?
Le but de ceci est d'obtenir le contenu d'une chaîne (initialement lue à partir d'une base de données) dans un flux, afin que le flux puisse être lu par un composant tiers.
NB : je ne peux pas modifier le composant tiers.
public System.IO.Stream CreateStream(string value)
{
var baseStream = new System.IO.MemoryStream();
var baseCopy = new System.IO.MemoryStream();
using (var writer = new System.IO.StreamWriter(baseStream, System.Text.Encoding.UTF8))
{
writer.Write(value);
writer.Flush();
baseStream.WriteTo(baseCopy);
}
baseCopy.Seek(0, System.IO.SeekOrigin.Begin);
return baseCopy;
}
Utilisé comme
public void Noddy()
{
System.IO.Stream myStream = CreateStream("The contents of this string are unimportant");
My3rdPartyComponent.ReadFromStream(myStream);
}
Idéalement, je recherche une méthode imaginaire appelée BreakAssociationWithBaseStream
, par exemple
public System.IO.Stream CreateStream_Alternate(string value)
{
var baseStream = new System.IO.MemoryStream();
using (var writer = new System.IO.StreamWriter(baseStream, System.Text.Encoding.UTF8))
{
writer.Write(value);
writer.Flush();
writer.BreakAssociationWithBaseStream();
}
return baseStream;
}
Réponses:
Si vous utilisez .NET Framework 4.5 ou version ultérieure, il existe une surcharge StreamWriter à l'aide de laquelle vous pouvez demander au flux de base de rester ouvert lorsque l'enregistreur est fermé .
Dans les versions antérieures de .NET Framework antérieures à 4.5,
StreamWriter
suppose qu'il possède le flux. Options:StreamWriter
; rincez-le.Close
/Dispose
mais met tout le reste en proxy. J'ai une implémentation de cela dans MiscUtil , si vous voulez le récupérer à partir de là.la source
leaveOpen
paramètre aprèsStreamWriter
sa création?Dispose
. La fin de la méthode ne le fait pas automatiquement. Il peut être finalisé plus tard s'il a un finaliseur, mais ce n'est pas la même chose - et on ne sait toujours pas quel danger vous prévoyez. Si vous pensez qu'il n'est pas sûr de renvoyer un àStreamWriter
partir d'une méthode car il pourrait être automatiquement supprimé par le GC, ce n'est tout simplement pas vrai.StreamWriter
n'a pas de finaliseur - je ne m'y attendais pas, précisément pour cette raison..NET 4.5 a une nouvelle méthode pour cela!
http://msdn.microsoft.com/EN-US/library/gg712853(v=VS.110,d=hv.2).aspx
la source
bufferSize
est1024
. Les détails sont ici .N'appelez tout simplement pas
Dispose
leStreamWriter
. La raison pour laquelle cette classe est supprimable n'est pas parce qu'elle contient des ressources non gérées, mais pour permettre l'élimination du flux qui pourrait lui-même contenir des ressources non gérées. Si la durée de vie du flux sous-jacent est gérée ailleurs, inutile de supprimer le rédacteur.la source
Flush
le travail au cas où il mettrait en mémoire tampon les données?Le flux de mémoire a une propriété ToArray qui peut être utilisée même lorsque le flux est fermé. To Array écrit le contenu du flux dans un tableau d'octets, quelle que soit la propriété Position. Vous pouvez créer un nouveau flux basé sur le flux dans lequel vous avez écrit.
la source
Stream.Position
peut pas être appelé après avoir été éliminé.Vous devez créer un descendant de StreamWriter et remplacer sa méthode dispose, en passant toujours false au paramètre disposing, cela forcera l'écrivain de flux à NE PAS se fermer, le StreamWriter appelle simplement dispose dans la méthode close, il n'est donc pas nécessaire de le remplacer (bien sûr, vous pouvez ajouter tous les constructeurs si vous le souhaitez, j'en ai juste un):
la source
disposing
drapeau est située dans leIDisposable
motif . Passer toujoursfalse
à laDispose(bool)
méthode de la classe de base signale essentiellement à laStreamWriter
qu'elle est appelée depuis le finaliseur (ce qui n'est pas le cas lorsque vous appelezDispose()
explicitement), et ne devrait donc accéder à aucun objet géré. C'est pourquoi il ne supprimera pas le flux de base. Cependant, la façon dont vous avez réalisé cela est un hack; il serait beaucoup plus simple de ne pas appelerDispose
en premier lieu!OwnedStream
, qui ignoreDispose(bool)
etClose
).