Returning a "Using" var - c#

I need to return a MemoryStream, and currently I do it like this:
String ICallbackEventHandler.GetCallbackResult()
{
using (var stream = new MemoryStream())
{
this._synth.Rate = this.Rate;
this._synth.Volume = this.Volume;
this._synth.SetOutputToWaveStream(stream);
string sText = this.Context.Items["data"].ToString();
this._synth.Speak(sText);
//rewind to beginning of stream
stream.Seek(0, SeekOrigin.Begin);
using (var nMp3Stream = new MemoryStream())
using (var rdr = new WaveFileReader(stream))
using (var wtr = new LameMP3FileWriter(nMp3Stream, rdr.WaveFormat, LAMEPreset.STANDARD))
{
rdr.CopyTo(wtr);
nMp3Stream.Position = 0;
return (String.Concat("data:audio/mpeg;base64,", Convert.ToBase64String(nMp3Stream.ToArray())));
}
}
}
But I don't think that's the proper way. I guess I shouldn't return a using variable, right?
If not, how could I do this? I need to dispose the MemoryStream, I think. When should I do this, or should I let the GC do this?

I guess I shouldn't return a using variable, right?
You don't return "using var" at all.
You convert content of it into the string , and return that string instead.
return (String.Concat("data:audio/mpeg;base64,",
Convert.ToBase64String(nMp3Stream.ToArray())));
Here you create a new instance of a string, fill it with content of MemoryStream and return that instance.
I need to dispose the MemoryStream, I think.
Yes, you have to think about lifetime of your instances.
When should I do this, or should I let the GC do this?
In most scenarios it's you who have take care of it and you're doing it proper way, at least judging from the code sample provided.
But, a lot depends on your concrete application design and execution dynamics.
For example:
consider performance implication of converting memory stream into the string
consider that at the moment of conversion you allocate almost 2x memory: one for MemoryStream another for string

You are not actually returning the using variable in this code. The ToArray() call created a new array object with memory separate from the nMp3Stream object. Additionally, Convert.ToBase64String() created a new string object separate from the array, and String.Concat() created yet another string separate from the first string.
So while I question the efficiency of this code, especially as it relates to address exhaustion via the Garbage Collector Large Object Heap, it's certainly not going to run into any problems with using.
If you're interested in fixing the performance issues, that's a much bigger question which is likely to involve changing how this method is used in the first place.
For the situations where you really do want to return the subject of a using block from a method, the pattern is typically to remove the using block, and instead move that block to the caller. In the case where the using subject needs a longer life span, perhaps as a class member, then the class should be written to implement IDisposable, so class instances can themselves be the subject of a using block.

Related

What risks in manipulating a provided stream multiple times

Given a stream by a user such that we expect them to manage the disposal of it through typical using
using(var stream = new MemoryStream())
{
MyMethod(stream);
}
Is there any risk to copying back to the stream after working on it. Specifically we have a method that populates the data, but we have a conditional need to sort the data. So MyMethod is something like this:
void MyMethod(Stream stream, bool sort = false)
{
//Stream is populated
stream.Position = 0;
if(sort)
{
Sort(stream);
}
}
void Sort(Stream stream)
{
using(var sortedStream = new MemoryStream)
{
//Sort per requirements into the new sorted local stream
sortedStream.Position = 0;
//Is this safe? Any risk of losing data or memory leak?
sortedStream.CopyTo(stream);
}
}
The thing to notice is we are populating the stream provided by the user and then sorting it into a local stream. Since the local stream is owned by the local method it is cleaned up but in converse we can NOT clean up the provided stream, but want to populate it with the local results.
To reiterate my question, is there anything wrong with this? Is there a risk of garbage data being in the stream or some other issue I am not thinking of?
Stream is an abstract class, and has a lot of different implementations. Not all streams can be written to, so in some cases the code may not work as expected, or could crash.
sortedStream.Position = 0;
sortedStream.CopyTo(stream);
You would need to check the CanSeek and CanWrite properties beforehand:
if (sortedStream.CanSeek & stream.CanWrite)
{
sortedStream.Position = 0;
sortedStream.CopyTo(stream);
}
else
{
// not supported
}
Whether a given stream support moving the position around and re-writing data over itself is going to depend on the specific stream. Some support it, and some don't. Not all streams are allowed to change their position, not all are able to write, not all are able to overwrite existing data, and some are able to do all of those things.
A well behaved stream shouldn't leak resources if you do any of those unsupported things; it ought to just throw an exception, but of course technically a custom stream could do whatever it wants, so you most certainly could write your own stream that leaks resources when changing the position. But of course at that point the bug of leaking a resource is in that stream's implementation, not in your code that sorts the data in the stream. The code you've shown here only needs to worry about a stream throwing an exception if an unsupported operation is performed.
I have no idea why you don't sort it before you insert it into the stream or why you use a stream at all when you access seems to be random-access, but technically, it's fine. You can do it. It will work.

Pass-Through Stream (not having to save to memory in the middle)

In my c# program, I am working with an object (third-party, so I have no way of changing its source code) that takes a stream in in its constructor (var myObject = new MyObject(stream);).
My challenge is that I need to make some changes to some of the lines of my file prior to it being ready to be given to this object.
To do this, I wrote the following code (which does work):
using (var st = new MemoryStream())
using (var reader = new StreamReader(path))
{
using (var writer = new StreamWriter(st))
{
while (!reader.EndOfStream)
{
var currentLine = reader.ReadLine().Replace(#"XXXX", #"YYYY");
writer.Write(currentLine);
}
writer.Flush();
st.Position = 0;
var myObject = new MyObject(st);
}
}
So, this does work, but it seems so inefficient since it is no longer really streaming the information, but storing it all in the memory stream before giving it through to the object.
Is there a way to create a transform / "pass-through stream" that will:
Read in each small amount from the streamreader
Make the adjustment on that small amount
Stream that amount through
So there won't be a large bit of memory storage in the middle?
Thanks!!
You just create your own class that derives from Stream, and implements the required methods that your MyObject needs.
Implement all your Read/ReadAsync methods by calling the matching Read/ReadAsync methods on your StreamReader. You can then modify the data as it passes through.
You'd have a bit of work to do if the modification requires some sort of understanding of the data as you'll be working in unknown quantities of bytes at a time. You would need to buffer the data to an extent required to do your necessary transformations, but how you do that is very specific to the transformation of the stream that you want to achieve.
Unfortunately the design of the C# Stream class is loaded down with lots of baggage, so implementing the entire API of Stream is quite a bit of work, but chances are your MyObject only calls one or two methods on Stream so a bit of experimentation should soon get it working.

Do C# Streams behave like pointers?

I've this class
class CacheHelper() {
private Dictionary<string, MemoryStream> cacher;
// ... other porps, f's...etc
public MemoryStream GetImageStream(string fileName)
{
if (!cacher.ContainsKey(fileName))
return null;
MemoryStream memStream = null;
cacher.TryGetValue(fileName, out memStream); // TODO
return memStream;
}
}
and I'm using it like this:
Stream fileStream = _cacheHelper.GetImageStream(filePath);
and When I'm done I'm closing fileStream like this:
if(fileStream!=null)
fileStream.Dispose();
I'm not sure what's going on underneath Stream implementation in C#, so I'm afraid that I'm closing the original MemoryStream (the one inside the internal cacher Dictionary) if I'm closing fileStream, i.e. implemented on top of pointers, or something.
A MemoryStream is a class. All classes are reference types which means that the variable you have is indeed a kind of pointer to the actual instance. What happens is that you pass a reference of your memory stream somewhere. If you don't want to close that stream, you should not do so.
A better implementation might be to either cache byte arrays or handle everything using streams inside the cache itself. Passing a stateful object from your cache to somewhere it's used and expecting it to keep it's original state is not such a good design. It's very easy to make mistakes that way.

Strings appear to be sticking around too long

In short, I've got an application that converts a flat data file into an XML file. It does this by populating objects and then serializing them to XML.
The problem I'm running into is that the Garbage Collector does not seem to be taking care of the serialized strings. 3500 record files are running up to OutOfMemoryExceptions before they finish. Something is fishy, indeed.
When I take the serialization out of the mix and simply pass an empty string, the memory consumption remains as expected, so I've ruled out the possibility that my intermediate objects (between flat file and xml) are the problem here. They seem to be collected as expected.
Can anyone help? How do I make sure these strings are disposed of properly?
Update: Some sample code
// myObj.Serialize invokes an XmlSerializer instance to handle its work
string serialized = myObj.Serialize();
myXmlWriter.WriteRaw(serialized);
This is basically where the problem is ocurring--if I take the string serialized out of play, the memory problems go away, too, even though I'm still transforming the flat file into objects, one at a time.
Update 2: Serialize method
public virtual string Serialize()
{
System.IO.StreamReader streamReader = null;
System.IO.MemoryStream memoryStream = null;
using (memoryStream = new MemoryStream())
{
memoryStream = new System.IO.MemoryStream();
Serializer.Serialize(memoryStream, this);
memoryStream.Seek(0, System.IO.SeekOrigin.Begin);
using (streamReader = new System.IO.StreamReader(memoryStream))
{
return streamReader.ReadToEnd();
}
}
}
You need to make sure they aren't referenced anywhere. Before an OutOfMemoryException is thrown, the GC is run. If it isn't recovering that memory, that means something is still holding on to it. Like others said, if you post some code, we might be able to help. Otherwise you can use a profiler or WinDbg/SOS to help figure out what is holding onto your strings.
Very curious indeed. I added the following dandy after each serialized record writes to the XmlWriter:
if (GC.GetTotalMemory(false) > 104857600)
{
GC.WaitForPendingFinalizers();
}
and wouldn't you know it, it's keeping it in check and it's processing without incident, never getting too far above the threshold I set. I feel like there should be a better way, but it almost seems like the code was executing too fast for the garbage collector to reclaim the strings in time.
Do you have an example of your code - how you're creating these strings? Are you breaking out into unmanaged code anywhere (which means you would be required to clean-up after yourself).
Another thought is how you are converting flat data file into XML. XML can be somewhat heavy depending on how you are building the file. If you are trying to hold the entire object in memory, it is very likely (easy to do, in fact) that you are running out of memory.
It sure looks like your method could be cleaned up to be just:
public virtual string Serialize()
{
StringBuilder sb = new StringBuilder();
using (StringWriter writer = new StringWriter(sb))
{
this.serializer.Serialize(writer, this);
}
return sb.ToString();
}
You are creating an extra MemoryStream for no reason.
But if you are writing the string to a file, then why don't you just send a FileStream to the Serialize() method?

int[] to byte[], am i forgetting something?

This is untested as i need to write more code. But is this correct and i feel like i am missing something, like this could be better written. Do i need the c.lose at the end? should i flush anything(i'll assume no if i do close())?
Byte[] buffer;
using (var m = new MemoryStream())
{
using (var binWriter = new BinaryWriter(m))
{
foreach (var v in wordIDs)
binWriter.Write(v);
binWriter.Close();
}
buffer = m.GetBuffer();
m.Close();
}
You don't need the .Close() calls (the automatic .Dispose() the using block generates takes care of those).
Also, you'll want to use .ToArray() on the MemoryStream, not .GetBuffer(). GetBuffer() returns the underlying buffer, no matter how much of it is used. ToArray() returns a copy that is the perfect length.
If you're using this to communicate with another program, make sure you and it agree on the order of the bytes (aka endianness). If you're using network byte-order, you'll need to flip the order of the bytes (using something like IPAddress.HostToNetworkOrder()), as network byte-order is big-endian, and BinaryWriter uses little-endian.
What is wordIDs, is it an enumeration or is it an Int32[]? You can use the following if it is just Int32[]:
byte[] bytes = new byte[wordIDs.Length * 4];
Buffer.BlockCopy(wordIDs, 0, bytes, 0, bytes.Length);
Otherwise, if wordIDs is an enumeration that you must step through, all you need to change is remove the m.Close (as mentioned) and use MemoryStream.ToArray (as mentioned).
Close is not needed here. The using statements will ensure the Dispose method on these types are called on exit and this will have the same effect as calling Close. In fact if you look at the code in reflector, you'll find that Close in both cases just proxies off to the Dispose method on both types.
Thus sayeth Skeet:
There's no real need to close either
a MemoryStream or a BinaryWriter, but
I think it's good form to use a using
statement to dispose of both - that
way if you change at a later date to
use something that really does need
disposing, it will fit into the same
code.
So you don't need the Close or the using statement, but using is idiomatic C#.
JaredPar's and Jonathan's answers are correct. If you want an alternative, you use BitConverter.GetBytes(int). So now your code turns into this
wordIDs.SelectMany(i => BitConverter.GetBytes(i));
I disagree with the Skeet here.
Whilst you may not need close by using using you are relying on the implementation of BinaryWriter and MemoryStream to do it for you in the Dispose method. This is true for framework types, but what if someone writes a Writer or Stream which doesn't do it?
Adding close does no harm and protects you against badly written classes.

Categories

Resources