File Exporter For IEnumerable of T

Scope

The purpose of this article is to show a solution for a file exporter based in a list of items regardless of type.

Introduction

Sometime ago the sample Export To CSV was published for Windows Store apps, this solution is generic, is dynamic because it uses reflection and allows export of a list of items to a CSV file. Windows Store apps uses Windows Runtime and reflection is a bit different from reflection in WPF, ASP.NET, and so on.

In this article we will create a sample for a common .Net project.

Description

For help in the sample, let's create a specific class Person.

  1. /// <summary>  
  2. /// Define the Person.  
  3. /// </summary>  
  4. public class Person  
  5. {  
  6.     /// <summary>  
  7.     /// Gets or sets the name.  
  8.     /// </summary>  
  9.     /// <value>The name.</value>  
  10.     public string Name { getset; }  
  11.     
  12.     /// <summary>  
  13.     /// Gets or sets the age.  
  14.     /// </summary>  
  15.     /// <value>The age.</value>  
  16.     public int Age { getset; }  
  17.     
  18.     /// <summary>  
  19.     /// Gets or sets the birthday.  
  20.     /// </summary>  
  21.     /// <value>The birthday.</value>  
  22.     public DateTime Birthday { getset; }  
  23.     
  24.     /// <summary>  
  25.     /// Gets or sets the country.  
  26.     /// </summary>  
  27.     /// <value>The country.</value>  
  28.     public string Country { getset; }  

In the class diagram we will have:



We will then create the Export class that will have a generic method, that uses a generic type T. Something such as the following:

  1. /// <summary>  
  2. /// Define the Export File.  
  3. /// </summary>  
  4. public static class Export  
  5. {  
  6.     /// <summary>  
  7.     /// Exporters the list of items that can include the specified include header line.  
  8.     /// </summary>  
  9.     /// <typeparam name="T">The generic type.</typeparam>  
  10.     /// <param name="includeHeaderLine">If set to <c>true</c> [include header line].</param>  
  11.     /// <param name="separator">The separator.</param>  
  12.     /// <param name="items">The items.</param>  
  13.     /// <returns>The content file.</returns>  
  14.     public static string Exporter<T>(bool includeHeaderLine, string separator, IEnumerable<T> items) where T : class  
  15.     {  
  16.         var sb = new StringBuilder();  
  17.     
  18.         // Get properties using reflection.  
  19.         var properties = typeof(T).GetProperties();  
  20.     
  21.         if (includeHeaderLine)  
  22.         {  
  23.             // add header line  
  24.             foreach (var property in properties)  
  25.             {  
  26.                 sb.Append(property.Name).Append(separator);  
  27.             }  
  28.             sb.Remove(sb.Length - 1, 1).AppendLine();  
  29.         }  
  30.     
  31.         // add value for each property.  
  32.         foreach (T item in items)  
  33.         {  
  34.             foreach (var property in properties)  
  35.             {  
  36.                 sb.Append(MakeValueFriendly(property.GetValue(item, null))).Append(separator);  
  37.             }  
  38.             sb.Remove(sb.Length - 1, 1).AppendLine();  
  39.         }  
  40.     
  41.         return sb.ToString();  
  42.     }  
  43.     
  44.     /// <summary>  
  45.     /// Makes the value friendly.  
  46.     /// </summary>  
  47.     /// <param name="value">The value.</param>  
  48.     /// <returns>The string converted.</returns>  
  49.     private static string MakeValueFriendly(object value)  
  50.     {  
  51.         if (value == null)  
  52.         {  
  53.             return string.Empty;  
  54.         }  
  55.     
  56.         if (value is DateTime)  
  57.         {  
  58.             if (((DateTime)value).TimeOfDay.TotalSeconds == 0)  
  59.             {  
  60.                 return ((DateTime)value).ToString("yyyy-MM-dd");  
  61.             }  
  62.             return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");  
  63.         }  
  64.         var output = value.ToString();  
  65.     
  66.         if (output.Contains(",") || output.Contains("""))  
  67.         {  
  68.             output = '"' + output.Replace(""""""") + '"';  
  69.         }  
  70.     
  71.         return output;  
  72.     }  

The method Exporter<T> will allow including a header with the properties name and allow to define the separador among each field value. It is very interesting because I can use the ListSeparator ( , or ; ), |, + or another we define.

The method MakeValueFriendly is only useful for format specific type like DateTime.

Now we can create a list of people and write it to a file, let's see how!

  1. /// <summary>  
  2. /// Define the Program.  
  3. /// </summary>  
  4. public class Program  
  5. {  
  6.     /// <summary>  
  7.     /// Defines the entry point of the application.  
  8.     /// </summary>  
  9.     /// <param name="args">The arguments.</param>  
  10.     static void Main(string[] args)  
  11.     {  
  12.         var people = GetPeople();  
  13.         var basePath = Directory.GetCurrentDirectory();  
  14.     
  15.         var fullPath = Path.Combine(basePath, "mycsvfile_includeHeader.csv");  
  16.     
  17.         // to cvs file  
  18.         File.WriteAllText(fullPath, Export.Exporter(true, System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator, people));  
  19.     
  20.         fullPath = Path.Combine(basePath, "myfile_includeHeader.txt");  
  21.     
  22.         // to a txt file  
  23.         File.WriteAllText(fullPath, Export.Exporter(true"+", people));  
  24.     
  25.     
  26.         fullPath = Path.Combine(basePath, "mycsvfile.csv");  
  27.     
  28.         // to cvs file  
  29.         File.WriteAllText(fullPath, Export.Exporter(true, System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator, people));  
  30.     
  31.         fullPath = Path.Combine(basePath, "myfile.txt");  
  32.     
  33.         // to a txt file  
  34.         File.WriteAllText(fullPath, Export.Exporter(true"|", people));  
  35.     }  
  36.     
  37.     /// <summary>  
  38.     /// Gets the people.  
  39.     /// </summary>  
  40.     /// <returns>The IEnumerable<Person>.</returns>  
  41.     private static IEnumerable<Person> GetPeople()  
  42.     {  
  43.         return new List<Person>  
  44.         {  
  45.             new Person { Name = "Mary", Age = 22, Birthday = new DateTime(1992, 03, 24), Country = "Ireland" },  
  46.             new Person { Name = "Peter", Age = 10, Birthday = new DateTime(2004, 01, 05), Country = "Portugal" },  
  47.             new Person { Name = "Anne", Age = 50, Birthday = new DateTime(1964, 11, 03), Country = "Spain" }  
  48.         };  
  49.     }  

In the sample provided, we get the people and then write it in a CSV file and a TXT file, where we selected both cases (with header and without).

The output:


Running the console application we will get the following output.

The CSV file with header:

 


The CSV file without header:
 

The txt file with header:
 

The txt  file without header:

Source code

The source code can be found in MSDN Samples .