Extension method for converting generic lists to CSV in C# [Updated]


Over a year ago I published a post which showed a c# extension method which can be use to convert a generic  list to CSV. Recently, I came across a problem in the code. It does not handle Nullable<T> properly. The following is an update to the code which fixes the Nullable<T> issues. I also added a cheap option which converts camel case headers to distinct words.

public static string ToCSV<T>(this IEnumerable<T> list, bool showheader = true, bool processHeaders = false)
 {
 var type = typeof(T);
 var properties = type.GetProperties();

//Setup expression constants
 var param = Expression.Parameter(type, "val");
 var doublequote = Expression.Constant("\"");
 var doublequoteescape = Expression.Constant("\"\"");
 var comma = Expression.Constant(",");

//Convert all properties to strings, escape and enclose in double quotes
 var propq = (from prop in properties
 let tostringcall = Expression.Call(typeof(Convert).GetMethod("ToString", new Type[] { typeof(object) }), Expression.Convert( Expression.Property(param, prop), typeof(object)))
 let replacecall = Expression.Call(tostringcall, typeof(string).GetMethod("Replace", new Type[] { typeof(String), typeof(String) }), doublequote, doublequoteescape)
 select Expression.Call(typeof(string).GetMethod("Concat", new Type[] { typeof(String), typeof(String), typeof(String) }), doublequote, replacecall, doublequote)
 ).ToArray();

//Convert an instance of the object to a single csv line
 var concatLine = propq[0];
 for (int i = 1; i < propq.Length; i++)
 concatLine = Expression.Call(typeof(string).GetMethod("Concat", new Type[] { typeof(String), typeof(String), typeof(String) }), concatLine, comma, propq[i]);

var method = Expression.Lambda<Func<T, String>>(concatLine, param).Compile();

if (showheader)
 {
 //Create header row
 var header = String.Join(",", properties.Select(p => processHeaders ? Regex.Replace(p.Name, "(\\B[A-Z])", " $1").Trim() : p.Name).ToArray());

return header + Environment.NewLine + String.Join(Environment.NewLine, list.Select(method).ToArray());
 }
 else
 {
 return String.Join(Environment.NewLine, list.Select(method).ToArray());
 }
 }
Advertisements