Close(), Dispose() and co. Just some question.

Just some info required about Close and Dispose of streams, just to be sure.
The following code as example of my doubts:

    public class Font : ID
    {

        private UnityEngine.Font _font;
        public UnityEngine.Font font
        {
            get
            {
                if (_font)
                    return _font;
                else
                    return Exception.nullFont (this.id); 
            }
        }

        //Constructor
        public Font () { }

        //Constructor args
        public Font (string id) 
        { 
            this.id = id;

            string _path = NM.IO.Path.GetExistingPath (NM.IO.Path.fontPath + id + NM.IO.File.nmf);

            if(System.IO.File.Exists(_path))
            {
                using(System.IO.FileStream fs = new System.IO.FileStream(_path, System.IO.FileMode.Open))
                {
                    using(System.IO.BinaryReader br = new System.IO.BinaryReader(fs))
                    {

                        _font = new UnityEngine.Font ();

                        if(!NM.IO.File.FileFormatMatch(this, br.ReadString ()))
                        {
                            _font = Exception.nullFont(_path);
                            return;
                        }

                        _font.name  = br.ReadString ();
                        string _mat = br.ReadString();

                        int _count = br.ReadInt32();
                        
                        CharacterInfo[] _chars = new CharacterInfo[_count];
                        
                        if(_count > 0)
                        {
                            for(int i = 0; i < _count; i++)
                            {
                                _chars [i].index = br.ReadInt32();

                                _chars [i].uvBottomLeft = new Vector2 (br.ReadSingle (), br.ReadSingle ());
                                _chars [i].uvBottomRight = new Vector2 (br.ReadSingle (), br.ReadSingle ());

                                _chars [i].uvTopLeft = new Vector2 (br.ReadSingle (), br.ReadSingle ());
                                _chars [i].uvTopRight = new Vector2 (br.ReadSingle (), br.ReadSingle ());

                                _chars [i].minX = br.ReadInt32 ();
                                _chars [i].minY = br.ReadInt32 ();

                                _chars [i].maxX = br.ReadInt32 ();
                                _chars [i].maxY = br.ReadInt32 ();

                                _chars [i].glyphHeight = br.ReadInt32 ();
                                _chars [i].glyphWidth = br.ReadInt32 ();

                                _chars [i].advance = br.ReadInt32 ();
                                _chars [i].bearing = br.ReadInt32 ();

                                /*
                                _chars[i].uv = new Rect(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
                                _chars[i].vert = new Rect(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
                                
                                _chars[i].width = br.ReadSingle();
                                _chars[i].flipped = br.ReadBoolean();
*/
                                
                            }
                            
                            if(_chars != null && _chars.Length > 0)
                                _font.characterInfo = _chars;

                            _font.material = NM.Machina.Cache.GetMaterialCache (_mat).material;
                        }
                        else
                        {
                            _font = Exception.nullFont(_path);
                            return;
                        }

                        br.Close ();
                    }
                    fs.Close();
                }
            }
            else
            {
                _font = Exception.nullFont(_path);
            }
        }
    }

This is my font class to import fonts at runtime. As you can see I close both FileStream and BinaryReader when is done. At one point however I have a return in case something wrong in the file I was reading happened, with a fallback.

Wanted to know a few things, would that return; prevent BinaryReader and FIleStream from closing, would be better to use Dispose and if having the using statement actualyl call dispose on itself.

Thanks.

When you use the using statement, it automatically calls Dispose() when you leave the using scope. Stream Dispose() also calls Close() if it hasn’t already been closed. So your Close() calls are redundant.

There’s a stackoverflow thread on this:
https://stackoverflow.com/questions/7524903/should-i-call-close-or-dispose-for-stream-objects

1 Like

The using() statement is just syntactic sugar for a try…finally construct.

No matter how you leave those using blocks, .Dispose() will be called on the associated object for each block.

As for Disposing a non-closed stream, I’m not sure. I would intuit that those objects have been written to call .Close on themselves when they get .Disposed, but I’d check the docs first to be sure.

Edit: @BlackPete above says you’re good to go.

1 Like

So in the case of BinaryReader and FileStream the Close methods really just call the Dispose(true) method.

So too does the Dispose/Finalize methods. Meaning that really… once GC occurs, even if you forgot to close the connection, it’ll get disposed at some point. Your calling it is just controlling WHEN that point is.

Lastly, you use the ‘using IDisposable’ syntax. Which really is a try/finally. This guarantees the calling of Dispose, no matter when you return.

1 Like

Thanks for the replies, this was more for a peace of mind situation, started having doubts when re reading some code.