No properties are mapped for type using csvHelper

Viewed 1157

I have two methods that return list of EmployeeCsv and CardCsv.

public class EmployeeCsv
{
    public string EmployeeId { get; set; }
    public string EmployeeName { get; set; }
}

public class CardCsv
{
    public string MaxCharge { get; set; }
    public string MaxDiscount { get; set; }
}

public List<EmployeeCsv> GetEmployeeList() {} // returns list of EmployeeCsv
public List<CardCsv> GetCardList() {} // returns list of CardCsv

I wanted to declare one type list for those two methods. So I changed them like below

public interface ITest {}
public class EmployeeCsv : ITest
{
    public string EmployeeId { get; set; }
    public string EmployeeName { get; set; }
}

public class CardCsv : ITest
{
    public string MaxCharge { get; set; }
    public string MaxDiscount { get; set; }
}

public List<ITest> GetEmployeeList() {}
public List<ITest> GetCardList() {}

Main:

void main()
{
    var records = new List<ITest>();
    records = GetEmployeeList();
    using (var writer = new StreamWriter(fileName))
    using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
    {
        csv.Configuration.ShouldQuote = (field, context) => true;
        csv.WriteRecords(records); // error here
    }
}

I get an error on saving after adding interface to those two classes. How can I fix this?

1 Answers

The problem here is that CsvHelper doesn't know the instance of the list items. You're telling it to process ITest items.

Consider the following:

var records = new List<ITest> { new EmployeeCsv(), new CardCsv() };

This is valid code. Now put yourself in CsvHelper's position. How would it create a CSV out of the items? Would it handle them as Employee, or Card? Neither. All it knows is that the items were ITest (a blank interface). Hence your error.

Instead complicating it with ITest, you're better off leaving the list items as their concrete types, but treating them as IEnumerable.

// Leave them as the derived types
public List<EmployeeCsv> GetEmployeeList() { .. }
public List<CardCsv> GetCardList() { .. }

void Main() {
    // Notice the IEnumerable so we can reuse WriteToFile()
    IEnumerable items = GetEmployeeList();
    WriteToFile(items); // employees

    items = GetCardList();
    WriteToFile(items); // cards
}
void WriteToFile(IEnumerable records) {
    ...
    csv.WriteRecords(records);
}

This way, CsvHelper can actually inspect the list and figure out the type, without the ITest confusion.

Edit: You should probably create a generic method, that way you can limit your items to ITest if you really want to, or you can leave it open.

// This needs to stay as its concrete type.
public List<EmployeeCsv> GetEmployeeList() { .. }

void Main() { 
    WriteToFile(GetEmployeeList()); 
}

// Get rid of the 'where' to make it accept things other than ITest.
void WriteToFile<T>(IEnumerable<T> records) where T : ITest
{   ...
    csv.WriteRecords(records);
}
Related