Meu problema raiz é que quando using
chama Dispose
um StreamWriter
, ele também descarta o BaseStream
(mesmo problema com Close
).
Eu tenho uma solução alternativa para isso, mas como você pode ver, envolve copiar o fluxo. Existe alguma maneira de fazer isso sem copiar o fluxo?
O objetivo disso é obter o conteúdo de uma string (originalmente lida de um banco de dados) em um fluxo, para que o fluxo possa ser lido por um componente de terceiros.
NB : Não consigo alterar o componente de terceiros.
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;
}
Usado como
public void Noddy()
{
System.IO.Stream myStream = CreateStream("The contents of this string are unimportant");
My3rdPartyComponent.ReadFromStream(myStream);
}
Idealmente, estou procurando um método imaginário chamado BreakAssociationWithBaseStream
, por exemplo,
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;
}
Respostas:
Se você estiver usando o .NET Framework 4.5 ou posterior, há uma sobrecarga do StreamWriter com a qual você pode solicitar que o fluxo de base seja deixado aberto quando o gravador for fechado .
Em versões anteriores do .NET Framework anteriores a 4.5,
StreamWriter
assume que é o proprietário do fluxo. Opções:StreamWriter
; apenas dê descarga.Close
/Dispose
mas faz proxy de todo o resto. Eu tenho uma implementação disso em MiscUtil , se você quiser pegá-la de lá.fonte
leaveOpen
parâmetro depois deStreamWriter
criado?Dispose
. A finalização do método não faz isso automaticamente. Ele pode ser finalizado mais tarde se tiver um finalizador, mas não é a mesma coisa - e ainda não está claro qual perigo você está prevendo. Se você acha que não é seguro retornar umStreamWriter
de um método porque ele poderia ser descartado automaticamente pelo GC, isso simplesmente não é verdade.StreamWriter
não tem um finalizador - eu não esperava, justamente por esse motivo..NET 4.5 tem um novo método para isso!
http://msdn.microsoft.com/EN-US/library/gg712853(v=VS.110,d=hv.2).aspx
fonte
bufferSize
é1024
. Os detalhes estão aqui .Simplesmente não ligue
Dispose
para oStreamWriter
. A razão pela qual essa classe é descartável não é porque ela contém recursos não gerenciados, mas para permitir o descarte do fluxo que poderia conter recursos não gerenciados. Se a vida do fluxo subjacente for tratada em outro lugar, não há necessidade de descartar o gravador.fonte
Flush
faria o trabalho no caso de armazenar dados em buffer?O fluxo de memória tem uma propriedade ToArray que pode ser usada mesmo quando o fluxo está fechado. To Array grava o conteúdo do fluxo em uma matriz de bytes, independentemente da propriedade Position. Você pode criar um novo fluxo com base no fluxo que você escreveu.
fonte
Stream.Position
pode ser chamado depois de eliminado.Você precisa criar um descendente do StreamWriter e substituir seu método dispose, sempre passando false para o parâmetro disposing, isso forçará o gravador de stream a NÃO fechar, o StreamWriter apenas chama dispose no método close, então não há necessidade de substituí-lo (é claro que você pode adicionar todos os construtores se quiser, eu só tenho um):
fonte
disposing
bandeira é parte doIDisposable
padrão . Sempre passarfalse
para oDispose(bool)
método da classe base basicamente sinaliza para oStreamWriter
que ele está sendo chamado do finalizador (o que não é assim quando você chamaDispose()
explicitamente) e, portanto, não deve acessar nenhum objeto gerenciado. Este é por isso que ele não vai descartar o fluxo de base. No entanto, a maneira como você conseguiu isso é um hack; seria muito mais simples simplesmente não ligarDispose
em primeiro lugar!OwnedStream
, que ignoraDispose(bool)
eClose
).