Search code examples
c#memory-leakstfsstreammemorystream

C# memory usage: value vs reference type for stream class usage in Team Foundation Server dlls


I am following the example here (How to attach a file to work item in TFS without physical file path?) to attach a file to a work item in TFS, by having a stream instead of having a physical file. I have the following code:

internal static void AddAttachment(WorkItemServer server, Project teamProject, string fileContent, WorkItem workItem)
{
    FileAttachment attachment = new FileAttachment();
    using (MemoryStream stream = new MemoryStream())
    {
        using (StreamWriter writer = new StreamWriter(stream))
        {
            writer.Write(fileContent);
            writer.Flush();
            stream.Position = 0;

            attachment.LocalFile = stream;
            attachment.AreaNodeUri = "";
            attachment.FileNameGUID = Guid.NewGuid();
            attachment.ProjectUri = teamProject.Uri.ToString();

            server.UploadFile(attachment);

            const string c_UpdatePackage = @"<validxml>";
            XmlDocument updatePackage = new XmlDocument();
            updatePackage.LoadXml(string.Format(c_UpdatePackage, workItem.Id /*work item ID*/, workItem.Rev /*work item latest revision*/, "Test attachment", attachment.FileNameGUID, DateTime.Now.ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'"), fileContent.Length, "John Smith", "http://localhost:8080/tfs/defaultcollection"));

            XmlElement outputPackage;
            string dbStamp;
            IMetadataRowSets metadata;
            server.Update(Guid.NewGuid().ToString(), updatePackage.DocumentElement, out outputPackage, null, out dbStamp, out metadata);
        }
    }
}

My question: During the assignment

attachment.LocalFile = stream;

Is stream copied to attachment.LocalFile by reference or by value? If it is copied by reference, I think the above code will not have a memory leak since it is disposing the stream in using:

using (MemoryStream stream = new MemoryStream()) { ... }

But if it copied by value(a copy of stream is made), this would leave a memory leak since FileAttachment is not being disposed, right? If memory leak is present, I think it is not possible to fix this memory leak since FileAttachment is not inheriting IDisposable. Below is the decompiled code resharper shows for FileAttachment:

namespace Microsoft.TeamFoundation.WorkItemTracking.Proxy
{
    public struct FileAttachment
    {
        private Stream m_localFile;
        ...
        public Stream LocalFile
        {
            get
            {
                return this.m_localFile;
            }
            set
            {
                this.m_localFile = value;
            }
        }
    }
 }

How can we confirm whether the stream object is being copied by reference or by value? If it is copied by value, how can we stop the memory leak?


Solution

  • An object is a reference type if it is a class, and a value type if it is a struct or enumerable. FileAttachment is a class.

    As such, the assignment attachment.LocalFile = stream; does not result in a memory leak because it is a copy by reference assignment.

    It should also be noted that the attachment.LocalFile property, once it exits that using() scope, will point to invalid data, and will throw an exception if anything attempts to access that property.