private void WriteProjectItems()

in src/StructuredLogger/BinaryLogger/BuildEventArgsWriter.cs [825:926]


        private void WriteProjectItems(IEnumerable items)
        {
            if (items == null)
            {
                Write(0);
                return;
            }

            var type = items.GetType();
            if (type.Name == "ItemDictionary`1")
            {
                var method = Reflector.GetEnumerateItemsPerTypeMethod(type);
                if (method != null)
                {
                    method.Invoke(items, new object[] { WriteItems });
                }

                // signal the end
                Write(0);
                return;
            }

            void WriteItems(string itemType, object itemList)
            {
                WriteDeduplicatedString(itemType);
                WriteTaskItemList((IEnumerable)itemList);
                CheckForFilesToEmbed(itemType, (IEnumerable)itemList);
            }

#if false
            if (items is ItemDictionary<ProjectItemInstance> itemInstanceDictionary)
            {
                // If we have access to the live data from evaluation, it exposes a special method
                // to iterate the data structure under a lock and return results grouped by item type.
                // There's no need to allocate or call GroupBy this way.
                itemInstanceDictionary.EnumerateItemsPerType((itemType, itemList) =>
                {
                    WriteDeduplicatedString(itemType);
                    WriteTaskItemList(itemList);
                    CheckForFilesToEmbed(itemType, itemList);
                });
            
                // signal the end
                Write(0);
            }
            // not sure when this can get hit, but best to be safe and support this
            else if (items is ItemDictionary<ProjectItem> itemDictionary)
            {
                itemDictionary.EnumerateItemsPerType((itemType, itemList) =>
                {
                    WriteDeduplicatedString(itemType);
                    WriteTaskItemList(itemList);
                    CheckForFilesToEmbed(itemType, itemList);
                });
            
                // signal the end
                Write(0);
            }
            else
#endif
            {
                string currentItemType = null;

                // Write out a sequence of items for each item type while avoiding GroupBy
                // and associated allocations. We rely on the fact that items of each type
                // are contiguous. For each item type, write the item type name and the list
                // of items. Write 0 at the end (which would correspond to item type null).
                // This is how the reader will know how to stop. We can't write out the
                // count of item types at the beginning because we don't know how many there
                // will be (we'd have to enumerate twice to calculate that). This scheme
                // allows us to stream in a single pass with no allocations for intermediate
                // results.
                Internal.Utilities.EnumerateItems(items, dictionaryEntry =>
                {
                    string key = (string)dictionaryEntry.Key;

                    // boundary between item types
                    if (currentItemType != null && currentItemType != key)
                    {
                        WriteDeduplicatedString(currentItemType);
                        WriteTaskItemList(reusableProjectItemList);
                        CheckForFilesToEmbed(currentItemType, reusableProjectItemList);
                        reusableProjectItemList.Clear();
                    }

                    reusableProjectItemList.Add(dictionaryEntry.Value);
                    currentItemType = key;
                });

                // write out the last item type
                if (reusableProjectItemList.Count > 0)
                {
                    WriteDeduplicatedString(currentItemType);
                    WriteTaskItemList(reusableProjectItemList);
                    CheckForFilesToEmbed(currentItemType, reusableProjectItemList);
                    reusableProjectItemList.Clear();
                }

                // signal the end
                Write(0);
            }
        }