0

Can I use tuples when writing to a csv file?

I am trying to reduce memory footprint by using tuple instead of a class instance.

The documentation does mention dynamic and anonymous types; but I don't see for value tuple. Also, how do I handle headers and custom formatting?

herme 0
  • 912
  • 1
  • 9
  • 23
  • [Writing a Header using CsvHelper? C#](https://stackoverflow.com/questions/38088379/writing-a-header-using-csvhelper-c-sharp). and [CSVHelper not formatting CSV](https://stackoverflow.com/questions/35369435/csvhelper-not-formatting-csv). ? – Luuk Nov 29 '22 at 18:13
  • Sure, a `ValueTuple<>` is a struct so its members can be serialized by CsvHelper. A few things to keep in mind: 1) The member names are `Item1`, `Item2` and so on, you might want to rename the headers. This is even true for value tuples, the "custom" names in an expression like `(string x, int y) tuple1 = ("hello", 10)` are just syntax sugar, see [this jon skeet answer](https://stackoverflow.com/a/46602134). – dbc Nov 29 '22 at 20:26
  • 2) Value tuple members are fields not properties, to serialize them automatically set `MemberTypes = MemberTypes.Fields` as shown in [this answer by Gerard](https://stackoverflow.com/a/68273689). You also asked, *how do I handle headers and custom formatting?* -- please [edit] your question to be more specific as to your requirements. What are your tuple inputs, and required CSV output? – dbc Nov 29 '22 at 20:27
  • I don't have a class, so I can't use WriteRecords() or WriteHeader(). I needed a way to write to a csv while still using csv helper. – herme 0 Nov 29 '22 at 20:55

2 Answers2

1

So @Luuk provided the idea. Since there is no class, have to use WriteField() and NextRecord() to write the header and the rows:

var rows = new (int Id, string Name, DateTime BornOn)[]
{
    (1, "Jack", new DateTime(2000, 1, 1)),
    (2, "Jill", new DateTime(1990, 3, 13)),
    (3, "McDonald", new DateTime(1970, 5, 12)),
    (4, "Burger King", new DateTime(1880, 8, 22)),
    (5, "Colonel Sanders", new DateTime(1960, 6, 11)),
};

using (var sw = new StreamWriter(@"test.csv"))
using (var csv = new CsvWriter(sw, CultureInfo.InvariantCulture))
{
    csv.WriteField("#");
    csv.WriteField("Name");
    csv.WriteField("DoB");
    csv.NextRecord();

    foreach (var r in rows)
    {
        csv.WriteField(string.Format("{0:000000}", r.Id));
        csv.WriteField(r.Name);
        csv.WriteField(r.BornOn.ToString("MM/dd/yyyy"));
        csv.NextRecord();
    }
}
herme 0
  • 912
  • 1
  • 9
  • 23
1

You can use WriteRecords with a ValueTuple. You just need to use @dbc's comment and set the MemberTypes in the CsvConfiguration to MemberTypes.Fields.

void Main()
{
    var rows = new (int Id, string Name, DateTime BornOn)[]
    {
        (1, "Jack", new DateTime(2000, 1, 1)),
        (2, "Jill", new DateTime(1990, 3, 13)),
        (3, "McDonald", new DateTime(1970, 5, 12)),
        (4, "Burger King", new DateTime(1880, 8, 22)),
        (5, "Colonel Sanders", new DateTime(1960, 6, 11)),
    };
    
    var config = new CsvConfiguration(CultureInfo.InvariantCulture)
    {
        MemberTypes = CsvHelper.Configuration.MemberTypes.Fields
    };

    //using (var writer = new StreamWriter("path\\to\\file.csv"))
    using (var csv = new CsvWriter(Console.Out, config))
    {
        csv.Context.RegisterClassMap<ValueTupleMap>();
        
        csv.WriteRecords(rows);
    }
}

public class ValueTupleMap : ClassMap<ValueTuple<int,string,DateTime>>
{
    public ValueTupleMap()
    {
        Map(m => m.Item1).Name("#");
        Map(m => m.Item2).Name("Name");
        Map(m => m.Item3).Name("DoB");
    }
}
David Specht
  • 7,784
  • 1
  • 22
  • 30