Dumpify Documentation

repository·main·Indexed 22 days ago

https://github.com/moaidhathot/dumpify

A C# library providing configurable .Dump() extension methods for Console Applications. It enables developers to inspect objects in a structured, colorful format across Console, Debug, or Trace outputs. Features include global and local configuration via DumpConfig, custom type handlers, nesting depth control, and support for LINQ query chaining.

Tokens
40.2K
Snippets
158
Records
187
Agent score
74%

What's inside Dumpify

  1. Overview of Dumpify features

    main

    Dumpify is a debugging and visualization tool for .NET console applications. Its features are categorized into three main areas:

    Display Features

    • Labels: Add descriptive headers to output.
    • Table Formatting: Configure borders, headers, and alignment.
    • Color Themes: Customize colors for all value types.
    • Type Names: Control how type names are displayed.

    Data Control

    • Member Filtering: Control which properties, fields, or private members are displayed.
    • Circular References: Safe handling of recursive/circular object structures.
    • Collections: Specialized rendering for arrays, lists, and dictionaries.
    • Depth Limiting: Prevent excessive nesting in complex objects.

    Extensibility

    • Custom Type Handlers: Define custom rendering logic for specific types.
    • Output Targets: Support for Console, Debug, Trace, or custom outputs.
    • Custom Renderers: Ability to implement your own rendering engine.
  2. Configure TableConfig for object rendering

    main

    The TableConfig class allows you to control the visual layout of tables when rendering objects. You can customize headers, row separators, indices, column wrapping, table width, and member type visibility.

    Use the tableConfig parameter in the .Dump() method to apply settings to a single call, or modify DumpConfig.Default.TableConfig to apply settings globally to your entire application.

    var tableConfig = new TableConfig
    {
        ShowArrayIndices = true,
        ShowTableHeaders = true,
        ShowRowSeparators = true,
        ShowMemberTypes = true,
        ExpandTables = false,
        NoColumnWrapping = false,
        BorderStyle = TableBorderStyle.Rounded
    };
    
    obj.Dump(tableConfig: tableConfig);
  3. How Dumpify handles circular references

    main

    Dumpify prevents infinite loops and stack overflows by tracking object references during rendering. When the engine encounters an object instance it has already visited in the current graph, it displays a reference indicator instead of recursing.

    Key technical behaviors:

    • Reference Tracking: Detection is based on object identity (reference equality), not value equality. Two different objects with identical property values are rendered fully. The same object instance appearing multiple times is detected as a cycle.
    • Value Types: Value types cannot cause circular references as they are copied.
    • Scenarios Supported: Self-references, parent-child relationships, linked lists, graph structures, and Entity Framework navigation properties.
    // Not circular - different instances with same values
    var a = new Point { X = 1, Y = 2 };
    var b = new Point { X = 1, Y = 2 };
    new[] { a, b }.Dump();  // Both rendered fully
    
    // Circular - same instance
    var c = new Node { Value = 1 };
    new[] { c, c }.Dump();  // Second reference detected
  4. Configure TruncationMode for collections

    main

    The TruncationMode enum determines how collections are displayed when they exceed the MaxCollectionCount limit. You can set this globally for all dumps or override it on a per-call basis.

    Available Modes

    • Head: Shows the first $N$ elements and truncates the rest at the end.
    • Tail: Shows the last $N$ elements and truncates the beginning.
    • HeadAndTail: Shows the first $N/2$ elements and the last $N/2$ elements, with a truncation marker in the middle.

    Best Practices

    • Use Head for ordered data, logs, or time-series where the start is most important.
    • Use Tail for logs or queues where the most recent items are at the end.
    • Use HeadAndTail to get a sense of both the start and end of a collection simultaneously.
    // Global configuration
    DumpConfig.Default.TruncationConfig.Mode = TruncationMode.HeadAndTail;
    DumpConfig.Default.TruncationConfig.MaxCollectionCount = 10;
    
    // Per-call override
    var truncationConfig = new TruncationConfig
    {
        Mode = TruncationMode.Tail,
        MaxCollectionCount = 5
    };
    myLargeList.Dump(truncationConfig: truncationConfig);
  5. Understand Dumpify's Configuration Hierarchy

    main

    Dumpify uses a layered configuration system where settings are applied in a specific order of precedence:

    1. Per-Dump Configuration: Options passed directly to the .Dump() method calls. These always take precedence.
    2. Global Configuration: Default settings defined via DumpConfig.Default. These apply to all dumps unless overridden by a per-dump call.

    Use Global Configuration to set baseline behavior for your entire application, and Per-Dump Configuration to handle specific edge cases or unique formatting requirements for a single object.

  6. Use MemberFilterContext to filter members during rendering

    main

    The MemberFilterContext struct provides the necessary context to decide whether a specific member (property or field) should be included in the output during rendering. It is used within filter functions configured via DumpConfig.Default.MembersConfig.MemberFilter (for global configuration) or the memberFilter parameter on individual Dump method calls (for per-call configuration).

    Properties

    • Member (IValueProvider): The member being filtered. Use this to access metadata like Name, MemberType, or reflection Info.
    • Value (object?): The actual value of the member. Note: This is lazily evaluated and only accessed when you call the property. Avoid accessing this if your filter logic can be satisfied by metadata alone to improve performance.
    • Source (object): The parent object containing the member.
    • Depth (int): The current rendering depth (where 0 is the root object).
    // Global configuration
    DumpConfig.Default.MembersConfig.MemberFilter = ctx => ctx.Value is not null;
    
    // Per-call configuration
    myObject.Dump(memberFilter: ctx => ctx.Depth < 2);
  7. Use MemberFilterContext for advanced filtering

    main

    The MemberFilterContext struct is passed to the MemberFilter delegate, providing the necessary metadata and state to make granular filtering decisions at runtime.

    Context Properties

    PropertyTypeDescription
    MemberIValueProviderThe member metadata (includes Name, Info, and MemberType)
    Valueobject?The actual value of the member (lazy-evaluated)
    SourceobjectThe parent object containing this member
    DepthintCurrent rendering depth (0 = root level)
  8. Render common .NET collection types

    main

    Dumpify provides intelligent rendering for various .NET collection types, displaying them as organized tables. Supported types include:

    • Arrays: Single and multi-dimensional.
    • Lists: List<T>, IList<T>.
    • Dictionaries: Dictionary<TKey, TValue>, IDictionary<TKey, TValue> (rendered with Key and Value columns).
    • Interfaces: IEnumerable<T>, ICollection<T>.
    • Sets/Queues/Stacks: HashSet<T>, Queue<T>, Stack<T>.
    • Immutable Collections: ImmutableArray<T>, ImmutableList<T>.
    • Tuples: Lists of tuples are supported.
    // Simple Array
    var numbers = new[] { 1, 2, 3, 4, 5 };
    numbers.Dump();
    
    // Dictionary
    var dict = new Dictionary<string, int> { ["one"] = 1 };
    dict.Dump();
    
    // List of Tuples
    var pairs = new List<(string Name, int Value)> { ("Alpha", 1) };
    pairs.Dump();
  9. Override or suppress Auto Labels

    main

    When UseAutoLabels is enabled, you can still control label behavior on a per-call basis:

    • Override: Pass an explicit string to Dump() to replace the auto-generated label.
    • Suppress: Pass null to the label parameter to remove the label entirely.
    DumpConfig.Default.UseAutoLabels = true;
    
    // Auto label: "complexExpression"
    complexExpression.Dump();
    
    // Explicit label overrides auto label
    complexExpression.Dump("My Custom Label");
    
    // Use null to suppress any label
    complexExpression.Dump(label: null);
  10. Decide between DumpOutput, IDumpOutput, and built-in outputs

    main

    Choose the appropriate output mechanism based on your requirements:

    ScenarioRecommendation
    Simple output to any TextWriterUse DumpOutput
    Need config adjustmentsUse DumpOutput with configFactory
    Complex custom behaviorImplement IDumpOutput directly
    Built-in targets (Console, Debug, Trace)Use Dumpify.Outputs.*
  11. Choose an output target for Dumpify

    main

    Dumpify provides several built-in methods to direct your object dumps to different destinations depending on your environment and use case:

    • Dump(): Uses the globally configured default (usually Console).
    • DumpConsole(): Always outputs to Console.WriteLine (ideal for terminal apps).
    • DumpDebug(): Outputs to System.Diagnostics.Debug (ideal for IDE debug windows like Visual Studio or VS Code).
    • DumpTrace(): Outputs to System.Diagnostics.Trace (ideal for trace listeners and logging frameworks).
    • DumpText(): Returns the formatted output as a string instead of writing it (ideal for logging, file output, or unit testing).
    // Examples of different targets
    myObject.Dump();          // Default
    myObject.DumpConsole();   // Terminal
    myObject.DumpDebug();     // IDE Debugger
    myObject.DumpTrace();     // Trace Listeners
    string text = myObject.DumpText(); // Capture as string
  12. Optimize performance in member filters

    main

    The Value property of MemberFilterContext is lazily evaluated. It only triggers the underlying GetValue() call when the property is actually accessed. To maximize performance, structure your filter logic to avoid accessing ctx.Value whenever possible, especially if you can determine the inclusion/exclusion using ctx.Member.Name or ctx.Member.MemberType first.

    Recommended Pattern: Check metadata (which is cheap) before checking the value (which may be expensive).

    // Good: Only evaluates Value when needed
    ctx => ctx.Member.Name != "ExpensiveProperty" && ctx.Value != null
    
    // Better: Short-circuiting avoids Value evaluation if Name matches
    ctx => ctx.Member.Name == "ExpensiveProperty" || ctx.Value != null