I have a system that reads input data from a Serial/UDP/TCP source. The input data is simply a CSV of different datattypes (e.g. DateTime, double, int, string). An example string might be:
2012/03/23 12:00:00,1.000,23,information,1.234
I currently have (untested) code that allows the user to specify which value in the CSV list goes to which property of a POCO.
So in the above example, i would have a object like so:
public class InputData
{
public DateTime Timestamp{get;set;}
public double Distance{get;set;}
public int Metres{get;set;}
public string Description{get;set;}
public double Height{get;set;}
}
Now in this class, i have a method to parse a CSV string and populate the properties. This method also requires "Mapping" information, as there is no guarantee which order the CSV data will arrive in - it is up to the user to define the correct order.
This is my Mapping class:
//This general class handles mapping CSV to objects
public class CSVMapping
{
//A dictionary holding Property Names (Key) and CSV indexes (Value)
//0 Based index
public IDictionary<string, int> Mapping { get; set; }
}
Now my method ParseCSV():
//use reflection to parse the CSV survey input
public bool ParseCSV(string pCSV, CSVMapping pMapping)
{
if (pMapping == null) return false;
else
{
Type t = this.GetType();
IList<PropertyInfo> properties = t.GetProperties();
//Split the CSV values
string[] values = pCSV.Split(new char[1] { ',' });
//for each property set its value from the CSV
foreach (PropertyInfo prop in properties)
{
if (pMapping.Mapping.Keys.Contains(prop.Name))
{
if (prop.GetType() == typeof(DateTime))
{
if (pMapping.Mapping[prop.Name] >= 0 && pMapping.Mapping[prop.Name] < values.Length)
{
DateTime tmp;
DateTime.TryParse(values[pMapping.Mapping[prop.Name]], out tmp);
prop.SetValue(this, tmp, null);
}
}
else if (prop.GetType() == typeof(short))
{
if (pMapping.Mapping[prop.Name] >= 0 && pMapping.Mapping[prop.Name] < values.Length)
{
double tmp;
double.TryParse(values[pMapping.Mapping[prop.Name]], out tmp);
prop.SetValue(this, Convert.ToInt16(tmp), null);
}
}
else if (prop.GetType() == typeof(double))
{
if (pMapping.Mapping[prop.Name] >= 0 && pMapping.Mapping[prop.Name] < values.Length)
{
double tmp;
double.TryParse(values[pMapping.Mapping[prop.Name]], out tmp);
prop.SetValue(this, tmp, null);
}
}
else if (prop.GetType() == typeof(string))
{
if (pMapping.Mapping[prop.Name] >= 0 && pMapping.Mapping[prop.Name] < values.Length)
{
prop.SetValue(this, values[pMapping.Mapping[prop.Name]], null);
}
}
}
}
return true;
}
}
Now for my question:
I potentially have several classes that will require this functionality. Would it be beneficial to implement a generic class or an extension class to do the parsing for me? Is my method a sound way to parse CSV data and popluate my object - or is there a better way to do this?
I have read other questions on dynamically parsing CSV, but all deal with the order being known before runtime, whereas i require the user to define the order.