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<Contact> ParseCsv(string filePath);
}
public class Reader : ICsvReader
{
public List<Contact> ParseCsv(string filePath)
{
List<String[]> rows = GetRows(filePath);
string[] headers = rows[0];
return MakeContacts(headers, rows);
}
private List<String[]> GetRows(string filePath)
{
List<Contact> users = new List<Contact>();
string[] lines = File.ReadAllLines(filePath);
var csv = from line in lines
select (line.Split(',')).ToArray();
return csv.ToList();
}
private List<Contact> MakeContacts(string[] headers, List<string[]> rows)
{
List<Contact> contacts = new List<Contact>();
// If we didn't know the headers we could contain values with their properties in a collection
// List<List<Dictionary<string, object>>> csv = new List<List<Dictionary<string, object>>>();
for (int i = 1; i < rows.Count; i++)
{
string[] row = rows[i];
Contact contact = new Contact();
for (int e = 0; e < 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;
}
}