'Fully qualified names for columns in CSV Helper (avoid duplicate column names and ensure idempotency)

I require the header of a CSV to represent the fully qualified name / path of properties on an object to ensure idempotency when converting to csv.

An example: if an object has multiple properties of the same type I would like to fully qualify the name. Consider the following structure:

public class Foo
{
    public DateTime? MyDateTime { get; set; }
    public string? MyDescription { get; set; }
}

public class MyContainer
{
    public Foo? MyFirstUsage { get; set; }
    public Foo? MySecondUsage { get; set; }
}

Under normal circumstances csv helper would create the header for 'MyContainer' as "MyDateTime,MyDescription,MyDateTime,MyDescription"

I'd like to avoid this and qualify the names resulting in a header of "MyFirstUsageMyDateTime,MyFirstUsageMyDescription,MySecondUsageMyDateTime,MySecondUsageMyDescription"

TL;DR: how can one override the way CSVHelper flattens objects to write the header so that the header represents the fully qualified path of a property, thus (theoretically) ensuring idempotency?

Edit: I created a small sample app to hopefully better explain the issue: https://github.com/JimHume/CsvHelperColumnNames/tree/main

Edit2: I forgot to mention that one requirement is for this to not be done via mapping--it needs to be done dynamically.



Solution 1:[1]

Update: Discovered you can use ReferenceHeaderPrefix in the configuration.

void Main()
{
    var mySample = new MyContainer
    {
        MyFirstUsage = new Foo
        {
            MyDateTime = DateTime.UtcNow.Subtract(TimeSpan.FromDays(1)),
            MyDescription = "This is the first usage"
        },
        MySecondUsage = new Foo
        {
            MyDateTime = DateTime.UtcNow.AddDays(1),
            MyDescription = "This is the second usage"
        }
    };

    var config = new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        ReferenceHeaderPrefix = (args) => $"{args.MemberName}",
    };

    using (var csvWriter = new CsvWriter(Console.Out, config))
    {
        csvWriter.WriteRecords(new[] { mySample });
    }
}

// You can define other methods, fields, classes and namespaces here
public class Foo
{
    public DateTime? MyDateTime { get; set; }
    public string MyDescription { get; set; }
}

public class MyContainer
{
    public Foo MyFirstUsage { get; set; }
    public Foo MySecondUsage { get; set; }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1