title: C# User Defined CSV Mapping to POCO
body: <p>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:</p>
  
  <pre><code>2012/03/23 12:00:00,1.000,23,information,1.234
  </code></pre>
  
  <p>I currently have (untested) code that allows the user to specify which value in the CSV list goes to which property of a POCO.</p>
  
  <p>So in the above example, i would have a object like so:</p>
  
  <pre><code>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;}
  } 
  </code></pre>
  
  <p>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.</p>
  
  <p>This is my Mapping class:</p>
  
  <pre><code>//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&lt;string, int&gt; Mapping { get; set; }
  }
  </code></pre>
  
  <p>Now my method ParseCSV():</p>
  
  <pre><code>//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&lt;PropertyInfo&gt; 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] &gt;= 0 &amp;&amp; pMapping.Mapping[prop.Name] &lt; 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] &gt;= 0 &amp;&amp; pMapping.Mapping[prop.Name] &lt; 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] &gt;= 0 &amp;&amp; pMapping.Mapping[prop.Name] &lt; 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] &gt;= 0 &amp;&amp; pMapping.Mapping[prop.Name] &lt; values.Length)
                      {
                          prop.SetValue(this, values[pMapping.Mapping[prop.Name]], null);
                      }
                  }
              }
          }
          return true;
      }
  }
  </code></pre>
  
  <p>Now for my question:</p>
  
  <p>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?</p>
  
  <p><em>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.</em></p>