Parsing CSV to specific format I've written this code to read CSV files written in a specific format. I would like to gather some feedback on where it could be improved. I'm trying to get into the Test-Driven-Development ideology so any way I could make the code play better with unit tests would be of particular interest to me.

An aspect I am not overly pleased with is the switch statement in the MatchHeaders function. I did try using enum representing the property names but I ran into an issue with not having constant value, and frankly it did not make the code read cleaner.

I am more interested in being pointed at what to look at and where, rather than being given code.

public class Contact
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public string FullAddress { get; set; }
    public string PostCode { get; set; }
    public string TelephoneNumber { get; set; }
    public string EmailAddress { get; set; }
}

public interface ICsvReader
{
    List&lt;Contact&gt; ParseCsv(string filePath);
}

public class Reader : ICsvReader
{
    public List&lt;Contact&gt; ParseCsv(string filePath)
    {
        List&lt;String[]&gt; rows = GetRows(filePath);
        string[] headers = rows[0];

        return MakeContacts(headers, rows);
    }

    private List&lt;String[]&gt; GetRows(string filePath)
    {
        List&lt;Contact&gt; users = new List&lt;Contact&gt;();
        string[] lines = File.ReadAllLines(filePath);
        var csv = from line in lines
                    select (line.Split(',')).ToArray();

        return csv.ToList();
    }

    private List&lt;Contact&gt; MakeContacts(string[] headers, List&lt;string[]&gt; rows)
    {
        List&lt;Contact&gt; contacts = new List&lt;Contact&gt;();
        // If we didn't know the headers we could contain values with their properties in a collection
        // List&lt;List&lt;Dictionary&lt;string, object&gt;&gt;&gt; csv = new List&lt;List&lt;Dictionary&lt;string, object&gt;&gt;&gt;();
        for (int i = 1; i &lt; rows.Count; i++)
        {
            string[] row = rows[i];
            Contact contact = new Contact();
            for (int e = 0; e &lt; row.Length; e++)
            {
                string header = headers[e];
                string value  = row[e];

                contact = MatchHeader(contact, header, value);
            }
            contacts.Add(contact);
        }
        return contacts;
    }

    private Contact MatchHeader(Contact user, string header, string value)
    {
        switch (header.ToLowerInvariant())
        {
            case "firstname":
                user.FirstName = value;
                break;
            case "lastname":
                user.LastName = value;
                break;
            case "dateofbirth":
                user.DateOfBirth = DateTime.Parse(value);
                break;
            case "fulladdress":
                user.FullAddress = value;
                break;
            case "postcode":
                user.PostCode = value;
                break;
            case "telephonenumber":
                user.TelephoneNumber = value;
                break;
            case "emailaddress":
                user.EmailAddress = value;
                break;
            default:
                break;
        }
        return user;
    }
}
Few comments:


Make your code more abstract, use IEnumerable instead of List

 public interface ICsvReader
 {
    IEnumerable&lt;Contact&gt; ParseCsv(string filePath);
 }

Provide an asynchronous version

public interface ICsvReader
{
    IEnumerable&lt;Contact&gt; ParseCsv(string filePath);
    Task&lt;IEnumerable&lt;Contact&gt;&gt; ParseCsvAsync(string filePath);
}

Use StreamReader instead of File.ReadAllLines, it has an async version that you can use in your ParseCsvAsync method

using(var stream = new StreamReader(filePath)){
 // read all lines
}

Try to use the var keyword for local variables, it makes refactoring easier

var rows = GetRows(filePath);

Use the beauty of deferred execution in C#

private IEnumerable&lt;Contact&gt; MakeContacts(string[] headers, List&lt;string[]&gt; rows)
{
    for (int i = 1; i &lt; rows.Count; i++)
    {
        string[] row = rows[i];
        Contact contact = new Contact();
        for (int e = 0; e &lt; row.Length; e++)
        {
            string header = headers[e];
            string value  = row[e];

            contact = MatchHeader(contact, header, value);
        }
        yield return contact;
     }
}

You can convert ToList immediately without calling ToArray

  private IEnumerable&lt;List&lt;string&gt;&gt; GetRows(string filePath)
  {
    // why you creating this List here???
    List&lt;Contact&gt; users = new List&lt;Contact&gt;();
    lines = File.ReadAllLines(filePath);
    var csv = (from line in lines
              select line.Split(',')).ToList();

    return csv;
  }

Consider @Snowbody suggestions about using a Dictionary instead of a massive switch.