Keywords: C# | Console Application | Table Drawing | String.Format | Performance Optimization
Abstract: This article provides an in-depth exploration of various methods for implementing efficient table drawing in C# console applications. It begins with basic table drawing using String.Format, then details a complete string-based table drawing solution including column width calculation, text center alignment, and table border drawing. The article compares the advantages and disadvantages of open-source libraries like ConsoleTables and CsConsoleFormat, and finally presents a generic table parser implementation based on reflection. Through comprehensive code examples and performance analysis, it helps developers choose the most suitable table drawing solution for their specific needs.
Basic Table Drawing Methods
In C# console applications, the most fundamental method for drawing tables is using the String.Format method. This method supports alignment format specifiers, allowing convenient control over column widths and alignment. For example: String.Format("|{0,5}|{1,5}|{2,5}|{3,5}|", arg0, arg1, arg2, arg3) generates a table row with 4 columns, each 5 characters wide. Here, {0,5} indicates the first parameter is right-aligned and occupies 5 character widths; for left alignment, use {0,-5}.
Complete Table Drawing Implementation
For more complex table requirements, a comprehensive table drawing system can be built. The following is an implementation based on string operations:
static int tableWidth = 73;
static void PrintLine()
{
Console.WriteLine(new string('-', tableWidth));
}
static void PrintRow(params string[] columns)
{
int width = (tableWidth - columns.Length) / columns.Length;
string row = "|";
foreach (string column in columns)
{
row += AlignCentre(column, width) + "|";
}
Console.WriteLine(row);
}
static string AlignCentre(string text, int width)
{
text = text.Length > width ? text.Substring(0, width - 3) + "..." : text;
if (string.IsNullOrEmpty(text))
{
return new string(' ', width);
}
else
{
return text.PadRight(width - (width - text.Length) / 2).PadLeft(width);
}
}This implementation includes three core methods: PrintLine for drawing table separators, PrintRow for constructing table rows, and AlignCentre for center-aligning text. The AlignCentre method handles overly long text by truncating it and adding ellipses.
Comparison of Open-Source Table Libraries
Beyond manual implementation, mature open-source libraries can simplify table drawing tasks.
ConsoleTables Library
ConsoleTables is one of the most popular console table formatting libraries, offering simple and intuitive usage:
var table = new ConsoleTable("one", "two", "three");
table.AddRow(1, 2, 3)
.AddRow("this line should be longer", "yes it is", "oh");
table.Write();This library supports multiple predefined table styles but can only handle single-line cells and does not support formatting.
CsConsoleFormat Library
For scenarios requiring complex formatting, CsConsoleFormat provides more powerful features:
new Grid { Stroke = StrokeHeader, StrokeColor = DarkGray }
.AddColumns(
new Column { Width = GridLength.Auto },
new Column { Width = GridLength.Auto, MaxWidth = 20 },
new Column { Width = GridLength.Star(1) },
new Column { Width = GridLength.Auto }
)
.AddChildren(
new Cell { Stroke = StrokeHeader, Color = White }
.AddChildren("Id"),
// More cell definitions...
)This library supports multi-line text, word wrapping, color settings, flexible column width control, and other advanced features.
Generic Table Parser Implementation
For handling dynamic data, a generic table parser can be constructed:
public static class TableParser
{
public static string ToStringTable<T>(
this IEnumerable<T> values,
string[] columnHeaders,
params Func<T, object>[] valueSelectors)
{
var arrValues = new string[values.Count() + 1, valueSelectors.Length];
// Fill headers
for (int colIndex = 0; colIndex < arrValues.GetLength(1); colIndex++)
{
arrValues[0, colIndex] = columnHeaders[colIndex];
}
// Fill data rows
for (int rowIndex = 1; rowIndex < arrValues.GetLength(0); rowIndex++)
{
for (int colIndex = 0; colIndex < arrValues.GetLength(1); colIndex++)
{
arrValues[rowIndex, colIndex] = valueSelectors[colIndex]
.Invoke(values.ElementAt(rowIndex - 1))?.ToString() ?? "";
}
}
return ToStringTable(arrValues);
}
private static int[] GetMaxColumnsWidth(string[,] arrValues)
{
var maxColumnsWidth = new int[arrValues.GetLength(1)];
for (int colIndex = 0; colIndex < arrValues.GetLength(1); colIndex++)
{
for (int rowIndex = 0; rowIndex < arrValues.GetLength(0); rowIndex++)
{
int newLength = arrValues[rowIndex, colIndex].Length;
if (newLength > maxColumnsWidth[colIndex])
{
maxColumnsWidth[colIndex] = newLength;
}
}
}
return maxColumnsWidth;
}
}This parser automatically calculates the maximum width for each column, ensuring neat table display. With reflection extensions, it can also automatically generate headers from object properties.
Performance Optimization Considerations
When dealing with large amounts of rapidly changing data, performance is a key consideration. Here are some optimization suggestions:
Use StringBuilder instead of string concatenation, especially when building table content in loops. Avoid frequent string allocations and garbage collection.
For static headers, precompute and cache format strings. Update dynamic data parts as needed.
Consider using double buffering: build new table content in one buffer and output it to the console all at once to reduce flickering.
For very frequent updates, consider updating only the changed parts instead of redrawing the entire table.
Practical Application Example
Combining best practices in console application development, here is a complete table display example:
class Program
{
static void Main(string[] args)
{
var data = new[]
{
new { Id = 1, Name = "John", Age = 25 },
new { Id = 2, Name = "Jane", Age = 30 },
new { Id = 3, Name = "Bob", Age = 35 }
};
Console.Clear();
// Use custom table drawing
PrintLine();
PrintRow("ID", "Name", "Age");
PrintLine();
foreach (var item in data)
{
PrintRow(item.Id.ToString(), item.Name, item.Age.ToString());
}
PrintLine();
Console.ReadLine();
}
// Table drawing method implementations...
}This example demonstrates how to integrate table drawing functionality into actual applications, providing good user experience and maintainable code structure.