C#: Export a List of Objects to CSV with LINQ, Attributes, and Generics

Have you ever needed to transform data from in-memory C# objects to a CSV flat-file of a specific format?  Here’s an easy way to get the job done with C#, LINQ, and Generics.

First you need the Attribute you will use to mark up the properties on your exportable class:

 
/// <summary>
/// The name of the column for the CSV
/// generated by a list of objects with
/// properties marked with this attribute,
/// if Export is true.  Uses Order to order
/// the properties on export
/// </summary>
public class CsvColumnNameAttribute : Attribute
{
	public bool Export { get; set; }
	public int Order { get; set; }
	public string Name { get; set; }
 
	public CsvColumnNameAttribute()
	{
		Export = true;
		Order = int.MaxValue; // so unordered columns are at the end
	}
 
}

And here is how you use the attributes to mark up your class so you can export a list of instantiated objects:

 
public class MyClassToExport
{
	[CsvColumn(Name = "Activation Date", Order = 1)]	
	public DateTime Date { get; set; }
 
	[CsvColumn(Name = "Full Name", Order = 2)]
	public string User { get; set; }
 
	[CsvColumn(Name = "Account Type", Order = 3)]
	public int Level { get; set; }
 
	[CsvColumn(Name = "Account Action", Order = 4)]
	public string Action { get; set; }
 
	[CsvColumn(Export = false)]
	public DateTime Added { get; set; }
}

Then you need to code to actually create the CSV using LINQ and Generics:

 
/// <summary>
/// Generate a CSV as a string from a list
/// of objects that have the CsvColumnNameAttribute
/// applied
/// </summary>
public string GetCsv<T>(List<T> csvDataObjects)
{
	PropertyInfo[] propertyInfos = typeof(T).GetProperties();
	var sb = new StringBuilder();
	sb.AppendLine(GetCsvHeaderSorted(propertyInfos));
	csvDataObjects.ForEach(d => sb.AppendLine(GetCsvDataRowSorted(d, propertyInfos)));
	return sb.ToString();
}
 
private string GetCsvDataRowSorted<T>(T csvDataObject, PropertyInfo[] propertyInfos)
{
	IEnumerable<string> valuesSorted = propertyInfos
		.Select(x => new
		{
			Value = x.GetValue(csvDataObject, null),
			Attribute = (CsvColumnNameAttribute)Attribute.GetCustomAttribute(x, typeof(CsvColumnNameAttribute), false)
		})
		.Where(x => x.Attribute != null && x.Attribute.Export)
		.OrderBy(x => x.Attribute.Order)
		.Select(x => GetPropertyValueAsString(x.Value));
	return String.Join(",", valuesSorted);
}
 
private string GetCsvHeaderSorted(PropertyInfo[] propertyInfos)
{
	IEnumerable<string> headersSorted = propertyInfos
		.Select(x => (CsvColumnNameAttribute)Attribute.GetCustomAttribute(x, typeof(CsvColumnNameAttribute), false))
		.Where(x => x != null && x.Export)
		.OrderBy(x => x.Order)
		.Select(x => x.Name);
	return String.Join(",", headersSorted);
}
 
private string GetPropertyValueAsString(object propertyValue)
{
	string propertyValueString;
 
	if (propertyValue == null)
		propertyValueString = "";
	else if (propertyValue is DateTime)
		propertyValueString = ((DateTime)propertyValue).ToString("dd MMM yyyy");
	else if (propertyValue is int)
		propertyValueString = propertyValue.ToString();
	else if (propertyValue is float)
		propertyValueString = ((float)propertyValue).ToString("#.####"); // format as you need it
	else if (propertyValue is double)
		propertyValueString = ((double)propertyValue).ToString("#.####"); // format as you need it
	else // treat as a string
		propertyValueString = @"""" + propertyValue.ToString().Replace(@"""", @"""""") + @""""; // quotes with 2 quotes
 
	return propertyValueString;
}

Once you have that code up in going in your application, you can export your list of objects to a CSV with just a couple lines of code:

 
// example usage
var export = new List<MyClassToExport>();
// TODO add items to list :)
var csv = GetCsv(export);

Hope this helps! And let me know if you have any suggestions or improvements.

This entry was posted in Attributes, C#, Generics, LINQ. Bookmark the permalink.

2 Responses to C#: Export a List of Objects to CSV with LINQ, Attributes, and Generics

  1. MeDif says:

    Hello,
    Can you please tell me how you create your csv file?

  2. Roshan Abraham says:

    Thanks a lot. I had to modify it a bit to get it working on Windows 8.1 Store App.
    Following are the modified methods :
    public string GetCsv(List csvDataObjects)
    {
    var objresult= typeof(T).GetRuntimeProperties();
    PropertyInfo[] propertyInfos = new PropertyInfo[objresult.Count()] ;
    int intCnt = 0;
    foreach (PropertyInfo objEach in objresult)
    {
    propertyInfos[intCnt] = objEach;
    intCnt++;
    }
    var sb = new StringBuilder();
    sb.AppendLine(GetCsvHeaderSorted(propertyInfos));
    foreach (T objEach in csvDataObjects)
    {
    sb.AppendLine(GetCsvDataRowSorted(objEach, propertyInfos));
    }

    return sb.ToString();
    }

    private string GetCsvDataRowSorted(T csvDataObject, PropertyInfo[] propertyInfos)
    {

    IEnumerable valuesSorted = propertyInfos
    .Select(x => new
    {
    Value = x.GetValue(csvDataObject, null),
    PropertyName = x.Name,
    Attribute = (CsvColumnNameAttribute) CustomAttributeExtensions.GetCustomAttribute(x, typeof(CsvColumnNameAttribute),false)
    })
    .Where(x => x.Attribute != null && x.Attribute.Export)
    .OrderBy(x => x.Attribute.Order)
    .Select(x => GetPropertyValueAsString(x.Value));
    return String.Join(“,”, valuesSorted);
    }

    private string GetCsvHeaderSorted(PropertyInfo[] propertyInfos)
    {
    IEnumerable headersSorted = propertyInfos
    .Select(x => (CsvColumnNameAttribute) CustomAttributeExtensions.GetCustomAttribute(x, typeof(CsvColumnNameAttribute), false))
    .Where(x => x != null && x.Export)
    .OrderBy(x => x.Order)
    .Select(x => x.Name);
    return String.Join(“,”, headersSorted);
    }

Leave a Reply

Your email address will not be published. Required fields are marked *