File: TaskItemData.cs
Web Access
Project: ..\..\..\src\Framework\Microsoft.Build.Framework.csproj (Microsoft.Build.Framework)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections;
using System.Collections.Generic;
 
#nullable disable
 
namespace Microsoft.Build.Framework
{
    /// <summary>
    /// Lightweight specialized implementation of <see cref="ITaskItem"/> only used for deserializing items.
    /// The goal is to minimize overhead when representing deserialized items.
    /// Used by node packet translator and binary logger.
    /// </summary>
    internal class TaskItemData : ITaskItem, IMetadataContainer
    {
        private static readonly Dictionary<string, string> _emptyMetadata = new Dictionary<string, string>();
 
        public string ItemSpec { get; set; }
        public IDictionary<string, string> Metadata { get; }
 
        public TaskItemData(string itemSpec, IDictionary<string, string> metadata)
        {
            ItemSpec = itemSpec;
            Metadata = metadata ?? _emptyMetadata;
        }
 
        /// <summary>
        /// Clone the task item and all metadata to create a snapshot
        /// </summary>
        /// <param name="original">An <see cref="ITaskItem"/> to clone</param>
        public TaskItemData(ITaskItem original)
        {
            ItemSpec = original.ItemSpec;
            var metadata = original.EnumerateMetadata();
 
            // Can't preallocate capacity because we don't know how large it will get
            // without enumerating the enumerable
            var dictionary = new Dictionary<string, string>();
            foreach (var item in metadata)
            {
                dictionary.Add(item.Key, item.Value);
            }
 
            Metadata = dictionary;
        }
 
        IEnumerable<KeyValuePair<string, string>> IMetadataContainer.EnumerateMetadata() => Metadata;
 
        void IMetadataContainer.ImportMetadata(IEnumerable<KeyValuePair<string, string>> metadata)
            => throw new InvalidOperationException($"{nameof(TaskItemData)} does not support write operations");
 
        public int MetadataCount => Metadata.Count;
 
        public ICollection MetadataNames => (ICollection)Metadata.Keys;
 
        public IDictionary CloneCustomMetadata()
        {
            // against the guidance for CloneCustomMetadata this returns the original collection.
            // Since this is only to be used for serialization and logging, consumers should not
            // modify the collection. We need to minimize allocations so avoid cloning here.
            return (IDictionary)Metadata;
        }
 
        public void CopyMetadataTo(ITaskItem destinationItem)
        {
            throw new InvalidOperationException($"{nameof(TaskItemData)} does not support write operations");
        }
 
        public string GetMetadata(string metadataName)
        {
            Metadata.TryGetValue(metadataName, out var result);
            return result;
        }
 
        public void RemoveMetadata(string metadataName)
        {
            throw new InvalidOperationException($"{nameof(TaskItemData)} does not support write operations");
        }
 
        public void SetMetadata(string metadataName, string metadataValue)
        {
            throw new InvalidOperationException($"{nameof(TaskItemData)} does not support write operations");
        }
 
        public override string ToString()
        {
            return $"{ItemSpec} Metadata: {MetadataCount}";
        }
    }
}