private void WriteTable()

in src/common/IO/Output/ConsoleOutput.cs [162:255]


        private void WriteTable<T>(IEnumerable<T> outputDataItems)
        {
            if (outputDataItems is null)
            {
                throw new ArgumentNullException(nameof(outputDataItems));
            }

            // Retrieve public properties of the data, and make sure that they are not to be ignored in Table format.
            var properties = typeof(T).GetProperties().Where(p => !Attribute.IsDefined(p, typeof(TableOutputFormatIgnore)));

            // Get the formatted data items
            var formattedDataItems = new List<List<string>>();
            bool hasSelectedElement = false;

            foreach (var item in outputDataItems)
            {
                var formattedDataItem = properties.Select(p =>
                {
                    var value = p.GetValue(item);

                    // Special case the "Selected" field
                    if (StringComparer.OrdinalIgnoreCase.Equals(p.Name, "Selected") && p.PropertyType == typeof(bool))
                    {
                        bool isSelected = (bool)value;
                        if (isSelected)
                        {
                            hasSelectedElement = true;
                            return ActiveRowHeader;
                        }
                        return InactiveRowHeader;
                    }

                    // Special case Date fields
                    if (p.PropertyType == typeof(DateTime))
                    {
                        return ((DateTime)value).FormatDateTimeUtcAsAgoString(roundToLargestUnitOfTime: true);
                    }

                    return value?.ToString() ?? string.Empty;
                }).ToList();
                formattedDataItems.Add(formattedDataItem);
            }

            // Get the table headers
            var headers = properties.Select(p =>
            {
                if (!StringComparer.OrdinalIgnoreCase.Equals(p.Name, "Selected"))
                {
                    var displayName = p.GetCustomAttributes(typeof(DisplayNameAttribute), false).SingleOrDefault();
                    if (displayName != null)
                    {
                        return ((DisplayNameAttribute)displayName).DisplayName;
                    }
                    else
                    {
                        return p.Name;
                    }
                }
                else
                {
                    // Special case for the "Selected" column
                    return hasSelectedElement ? InactiveRowHeader : ActiveRowHeader;
                }
            });

            // Calculate column widths
            var columnWidths = new List<int>();
            foreach (var header in headers)
            {
                columnWidths.Add(header.Length);
            }

            formattedDataItems.ExecuteForEach(formattedDataItem =>
            {
                for (var i = 0; i < formattedDataItem.Count; i++)
                {
                    columnWidths[i] = Math.Max(columnWidths[i], formattedDataItem[i]?.Length ?? 0);
                }
            });

            var formattedRowsToLog = new List<string>();
            formattedRowsToLog.Add(this.WriteTableRow(headers.ToList(), columnWidths));

            var headerUnderlines = columnWidths.Select(width => new string('-', width)).ToList();
            formattedRowsToLog.Add(this.WriteTableRow(headerUnderlines, columnWidths));

            foreach (var formattedDataItem in formattedDataItems)
            {
                formattedRowsToLog.Add(this.WriteTableRow(formattedDataItem, columnWidths));
            }

            var formattedOutputToLog = string.Join(Environment.NewLine, formattedRowsToLog);
            _log.WithoutTelemetry.Info($"Console output (Table):{Environment.NewLine}{formattedOutputToLog}");
        }