[C#] File exporter for IEnumerable of T

Scope

This article has the goal to show a solution for have a file exporter based in a list of items but not matter which type.

Introduction

Sometime ago was published the sample Export To CSV for Windows Store apps, this solution is generic, is dynamic because uses reflection and It allow to export a list of items to a csv file. In Windows Store apps uses Windows Runtime and reflection is a bit different from reflection in WPF, Asp.Net, …

In this sample ww will create the sample for a common .Net project.

Description

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

    /// 
    /// Define the Person.
    /// 
    public class Person
    {
        /// 
        /// Gets or sets the name.
        /// 
        /// The name.
        public string Name { get; set; }

        /// 
        /// Gets or sets the age.
        /// 
        /// The age.
        public int Age { get; set; }

        /// 
        /// Gets or sets the birthday.
        /// 
        /// The birthday.
        public DateTime Birthday { get; set; }

        /// 
        /// Gets or sets the country.
        /// 
        /// The country.
        public string Country { get; set; }
    }

in class diagram we will have

person
After it, we will create the Export class that will have a generic method, that uses a generic type T. Something like as following

 

    /// 
    /// Define the Export File.
    /// 
    public static class Export
    {
        /// 
        /// Exporters the list of items that can include the specified include header line.
        /// 
        /// <typeparam name="T">The generic type.
        ///If set totrue [include header line].
        ///The separator.
        ///The items.
        /// The content file.
        public static string Exporter(bool includeHeaderLine, string separator, IEnumerable items) where T : class
        {
            var sb = new StringBuilder();

            // Get properties using reflection. 
            var properties = typeof(T).GetProperties();

            if (includeHeaderLine)
            {
                // add header line
                foreach (var property in properties)
                {
                    sb.Append(property.Name).Append(separator);
                }
                sb.Remove(sb.Length - 1, 1).AppendLine();
            }

            // add value for each property. 
            foreach (T item in items)
            {
                foreach (var property in properties)
                {
                    sb.Append(MakeValueFriendly(property.GetValue(item, null))).Append(separator);
                }
                sb.Remove(sb.Length - 1, 1).AppendLine();
            }

            return sb.ToString();
        }

        /// 
        /// Makes the value friendly.
        /// 
        ///The value.
        /// The string converted.
        private static string MakeValueFriendly(object value)
        {
            if (value == null)
            {
                return string.Empty;
            }

            if (value is DateTime)
            {
                if (((DateTime)value).TimeOfDay.TotalSeconds == 0)
                {
                    return ((DateTime)value).ToString("yyyy-MM-dd");
                }
                return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss");
            }
            var output = value.ToString();

            if (output.Contains(",") || output.Contains("\""))
            {
                output = '"' + output.Replace("\"", "\"\"") + '"';
            }

            return output;
        } 
    }

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

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

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

    /// 
    /// Define the Program.
    /// 
    public class Program
    {
        /// 
        /// Defines the entry point of the application.
        /// 
        /// args">The arguments.
        static void Main(string[] args)
        {
            var people = GetPeople();
            var basePath = Directory.GetCurrentDirectory();

            var fullPath = Path.Combine(basePath, "mycsvfile_includeHeader.csv");

            // to cvs file
            File.WriteAllText(fullPath, Export.Exporter(true, System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator, people));

            fullPath = Path.Combine(basePath, "myfile_includeHeader.txt");

            // to a txt file
            File.WriteAllText(fullPath, Export.Exporter(true, "+", people));


            fullPath = Path.Combine(basePath, "mycsvfile.csv");

            // to cvs file
            File.WriteAllText(fullPath, Export.Exporter(true, System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator, people));

            fullPath = Path.Combine(basePath, "myfile.txt");

            // to a txt file
            File.WriteAllText(fullPath, Export.Exporter(true, "|", people));
        }

        /// 
        /// Gets the people.
        /// 
        /// The IEnumerable.
        private static IEnumerable GetPeople()
        {
            return new List
            {
                new Person { Name = "Mary", Age = 22, Birthday = new DateTime(1992, 03, 24), Country = "Ireland" },
                new Person { Name = "Peter", Age = 10, Birthday = new DateTime(2004, 01, 05), Country = "Portugal" },
                new Person { Name = "Anne", Age = 50, Birthday = new DateTime(1964, 11, 03), Country = "Spain" }
            };
        }
    }

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

The ouput

Running the console application we will get the output

folder

The CSV file with header

The CSV file without header

The txt file with header

The CSV file without header

Source Code

The source code can be found in MSDN Samples.