Search code examples
c#csvhelper

CsvHelper writing header from two types with mixed ordering


I am writing properties from two classes to a CSV using CsvHelper. I have maps for them both. The issue is I want the header/fields to be in the order of

filename, FooId, BarId, FooName, BarName
file.txt, f1, b1, myFoo, myBar

and it only shows up as

filename, FooId, FooName, BarId, BarName
file.txt, f1, myFoo, b1, myBar

Here is some relevant code

public class Foo {
    public string Filename { get; set; }
    public string Id { get; set; }
    public string Name { get; set; }
    
}

public class FooMap : ClassMap<Foo> {
    public FooMap() {
        Map(m => m.Filename).Index(0).Name("filename");
        Map(m => m.Id).Index(1).Name("FooId");
        Map(m => m.Name).Index(3).Name("FooName");
    }
}

public class Bar {
    public string Id { get; set; }
    public string Name { get; set; }
}

public class BarMap : ClassMap<Bar> {
    public BarMap() {
        Map(m => m.Id).Index(2).Name("BarId");
        Map(m => m.Name).Index(4).Name("BarName");
    }
}

public static void Main() {
    Foo foo1 = new("file.txt", "f1", "myFoo");
    Bar bar1 = new("b1", "myBar");
    using (var reader = new StreamReader("Path/to/my/csv"))
    using (var csv = new CsvWriter(reader, CultureInfo.InvariantCulture))
    {
        csv.Context.RegisterClassMap<FooMap>();
        csv.Context.RegisterClassMap<BarMap>();

        csv.WriteHeader<Foo>();
        csv.WriteHeader<Bar>();
        csv.NextRecord();

        while (csv.Read())
        {
             csv.WriteRecord(foo);
             csv.WriteRecord(bar);
             csv.NextRecord();
        }
}

The constructor for the class is basic. If you would like me to post it as well, I will! My main question is whether it's possible to mix the two classes within the maps as opposed to manually writing out each field.


Solution

  • You could combine them into a FooBar class and then map the FooBar class.

    void Main()
    {
        var records = new List<FooBar> 
        {
            new FooBar 
            {           
                Foo = new Foo { FileName = "file.txt", Id = "fi", Name = "myFoo"},
                Bar = new Bar { Id = "bi", Name = "myBar" }
            }
        };
        
        using (var csv = new CsvWriter(Console.Out, CultureInfo.InvariantCulture))
        {  
            csv.Context.RegisterClassMap<FooBarMap>();
            csv.WriteRecords(records);
        }
    }
    
    public class FooBar
    {
        public Foo Foo { get; set; }
        public Bar Bar { get; set; }
    }
    
    public class FooBarMap : ClassMap<FooBar>
    {
        public FooBarMap()
        {
            Map(x => x.Foo.FileName).Name("filename").Index(0);
            Map(x => x.Foo.Id).Name("FooId").Index(1);
            Map(x => x.Foo.Name).Name("FooName").Index(3);
            Map(x => x.Bar.Id).Name("BarId").Index(2);
            Map(x => x.Bar.Name).Name("BarName").Index(4);
        }
    }
    
    public class Foo
    {
        public string FileName { get; set; }
        public string Id { get; set; }
        public string Name { get; set; }
    }
    
    public class Bar
    {
        public string Id { get; set; }
        public string Name { get; set; }
    }