1
votes
public class Class1
{
    [CsvField(Name = "Field1")]
    public int Field1 { get; set; }

    [CsvField(Name = "Field2")]
    public int Field2 { get; set; }

    [CsvField(Ignore = true)]
    public Class2 Class2 { get; set; }

    [CsvField(Ignore = true)]
    public Class3 Class3 { get; set; }
}

public class Class2
{
    [CsvField(Name = "Field3")]
    public int Field3 { get; set; }

    [CsvField(Name = "Field4")]
    public int Field4 { get; set; }
}

public class Class3
{
    [CsvField(Name = "Field5")]
    public int Field5 { get; set; }

    [CsvField(Name = "Field6")]
    public int Field6 { get; set; }
}

I'm using CSVHelper to write data into CSV file. I need write Class1 with header like this:

Field1, Field2, Field3, Field4, Field5, Field6

How I can do this?

1
You could just add extra public Properties that access the methods of Class2 and Class3. Then apply the attributes to those properties instead.ManoDestra

1 Answers

1
votes

This is an old question, so you likely already have an answer. You have a few options.

Option 1 (that I know will work) Documentation

You just need to manually write out the contents of the CSV, below is some code that will get you started, but you'll need to modify based on how the contents of your objects are stored.

using (var stream = new MemoryStream())
{
    using (var streamWriter = new StreamWriter(stream))
    using (var csv = new CsvWriter(streamWriter))
    {
        // Write out header
        csv.WriteField("Field1");
        csv.WriteField("Field2");
        csv.WriteField("Field3");
        csv.WriteField("Field4");
        csv.WriteField("Field5");
        csv.WriteField("Field6");

        // Write out end line
        csv.NextRecord();

        //Pseudocode
        foreach (var item in Class1Collection)
        {
            csv.WriteField(item.Field1);
            csv.WriteField(item.Field2);
            csv.WriteField(item.Class2.Field3);
            csv.WriteField(item.Class2.Field4);
            csv.WriteField(item.Class3.Field5);
            csv.WriteField(item.Class3.Field6);

            // Write out end line
            csv.NextRecord();
        }
    }
}

Option 2 (have used, but not like this) Documentation

Your second option is to write a custom CSVMap that tells the CSVWriter how to handle the nested classes. I'm not sure how to deal with the name, so you might have to work through that.

public sealed class Class1CSVMap : CsvClassMap<RemittanceFormModel>
{
    public Class1CSVMap()
    {
        Map(m => m.Field1).Name("Field1");
        Map(m => m.Field2).Name("Field2");
        Map(m => m.Class2).Name("Field3,Field4").TypeConverter<Class2Converter>();
        Map(m => m.Class3).Name("Field5,Field6").TypeConverter<Class3Converter>();
    }
}

Then you have your converter, one for Class2 and one for Class3

public class Class2Converter : DefaultTypeConverter
{
    public override string ConvertToString(TypeConverterOptions options, object model)
    {
        var result = string.Empty;

        var classObject = model as Class2;

        if (classObject != null)
        {
            result = string.Format("{0},{1}", classObject.Field3, classObject.Field4);
        }

        return result;
    }
}

Option 3 (have never used) Documentation

You can do an inline converter instead of creating a separate class. I've never tried this, but it should work.

public sealed class Class1CSVMap : CsvClassMap<Class1>
{
    public Class1CSVMap()
    {
            Map(m => m.Field1).Name("Field1");
            Map(m => m.Field2).Name("Field2");
            Map(m => m.Class2).Name("Field3,Field4").ConvertUsing(row =>  string.Format("{0},{1}", row.Field3, row.Field4); );
            Map(m => m.Class3).Name("Field5,Field6").ConvertUsing(row =>  string.Format("{0},{1}", row.Field5, row.Field6); );
    }
}