Last active
November 8, 2015 22:19
-
-
Save dibley1973/3032d1c33f18b188d51a to your computer and use it in GitHub Desktop.
ToDelimitedText() extension for List<T>
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Reflection; | |
using System.Text; | |
namespace Gists.Extensions.ListOfTExtentions | |
{ | |
public static class ListOfTExtentions | |
{ | |
/// <summary> | |
/// Converst this instance to delimited text. | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="instance">The instance.</param> | |
/// <param name="delimiter">The delimiter.</param> | |
/// <param name="includeHeader"> | |
/// if set to <c>true</c> then the header row is included. | |
/// </param> | |
/// <param name="trimTrailingNewLineIfExists"> | |
/// If set to <c>true</c> then trim trailing new line if it exists. | |
/// </param> | |
/// <returns></returns> | |
public static string ToDelimitedText<T>(this List<T> instance, | |
string delimiter, | |
bool includeHeader = false, | |
bool trimTrailingNewLineIfExists = false) | |
where T : class, new() | |
{ | |
int itemCount = instance.Count; | |
if (itemCount == 0) return string.Empty; | |
var properties = GetPropertiesOfType<T>(); | |
int propertyCount = properties.Length; | |
var outputBuilder = new StringBuilder(); | |
AddHeaderIfRequired(outputBuilder, includeHeader, properties, propertyCount, delimiter); | |
for (int itemIndex = 0; itemIndex < itemCount; itemIndex++) | |
{ | |
T listItem = instance[itemIndex]; | |
AppendListItemToOutputBuilder(outputBuilder, listItem, properties, propertyCount, delimiter); | |
AddNewLineIfRequired(trimTrailingNewLineIfExists, itemIndex, itemCount, outputBuilder); | |
} | |
var output = outputBuilder.ToString(); | |
return output; | |
} | |
private static void AddHeaderIfRequired(StringBuilder outputBuilder, | |
bool includeHeader, | |
PropertyInfo[] properties, | |
int propertyCount, | |
string delimiter) | |
{ | |
if (!includeHeader) return; | |
for (int propertyIndex = 0; propertyIndex < properties.Length; propertyIndex += 1) | |
{ | |
var property = properties[propertyIndex]; | |
var propertyName = property.Name; | |
outputBuilder.Append(propertyName); | |
AddDelimiterIfRequired(outputBuilder, propertyCount, delimiter, propertyIndex); | |
} | |
outputBuilder.Append(Environment.NewLine); | |
} | |
private static void AddDelimiterIfRequired(StringBuilder outputBuilder, int propertyCount, string delimiter, | |
int propertyIndex) | |
{ | |
bool isLastProperty = (propertyIndex + 1 == propertyCount); | |
if (!isLastProperty) | |
{ | |
outputBuilder.Append(delimiter); | |
} | |
} | |
private static void AddNewLineIfRequired(bool trimTrailingNewLineIfExists, int itemIndex, int itemCount, | |
StringBuilder outputBuilder) | |
{ | |
bool isLastItem = (itemIndex + 1 == itemCount); | |
if (!isLastItem || !trimTrailingNewLineIfExists) | |
{ | |
outputBuilder.Append(Environment.NewLine); | |
} | |
} | |
private static void AppendListItemToOutputBuilder<T>(StringBuilder outputBuilder, | |
T listItem, | |
PropertyInfo[] properties, | |
int propertyCount, | |
string delimiter) | |
where T : class, new() | |
{ | |
for (int propertyIndex = 0; propertyIndex < properties.Length; propertyIndex += 1) | |
{ | |
var property = properties[propertyIndex]; | |
var propertyValue = property.GetValue(listItem); | |
outputBuilder.Append(propertyValue); | |
AddDelimiterIfRequired(outputBuilder, propertyCount, delimiter, propertyIndex); | |
} | |
} | |
private static PropertyInfo[] GetPropertiesOfType<T>() where T : class, new() | |
{ | |
Type itemType = typeof(T); | |
var properties = itemType.GetProperties(BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.Public); | |
return properties; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using Microsoft.VisualStudio.TestTools.UnitTesting; | |
using Gists.Extensions.ListOfTExtentions; | |
namespace Gists_Tests.ExtensionTests.ListOfTExtentionTests | |
{ | |
[TestClass] | |
public class ListOfT_ToDelimitedTextTests | |
{ | |
#region Mock Data | |
private class ComplexObject | |
{ | |
public int Id { get; set; } | |
public string Name { get; set; } | |
public bool Active { get; set; } | |
} | |
#endregion | |
#region Tests | |
[TestMethod] | |
public void ToDelimitedText_ReturnsCorrectNumberOfRows() | |
{ | |
// ARRANGE | |
var itemList = new List<ComplexObject> | |
{ | |
new ComplexObject {Id = 1, Name = "Sid", Active = true}, | |
new ComplexObject {Id = 2, Name = "James", Active = false}, | |
new ComplexObject {Id = 3, Name = "Ted", Active = true} | |
}; | |
const string delimiter = ","; | |
const int expectedRowCount = 3; | |
const bool includeHeader = false; | |
const bool trimTrailingNewLineIfExists = true; | |
// ACT | |
string result = itemList.ToDelimitedText(delimiter, includeHeader, trimTrailingNewLineIfExists); | |
var lines = result.Split(new[] { Environment.NewLine }, StringSplitOptions.None); | |
var actualRowCount = lines.Length; | |
// ASSERT | |
Assert.AreEqual(expectedRowCount, actualRowCount); | |
} | |
[TestMethod] | |
public void ToDelimitedText_IncludesHeaderRow_WhenSet() | |
{ | |
// ARRANGE | |
var itemList = new List<ComplexObject> | |
{ | |
new ComplexObject {Id = 1, Name = "Sid", Active = true}, | |
new ComplexObject {Id = 2, Name = "James", Active = false}, | |
new ComplexObject {Id = 3, Name = "Ted", Active = true} | |
}; | |
const string delimiter = ","; | |
const int expectedRowCount = 4; | |
const bool includeHeader = true; | |
const bool trimTrailingNewLineIfExists = true; | |
const string expectedHeader = @"Id,Name,Active"; | |
// ACT | |
string result = itemList.ToDelimitedText(delimiter, includeHeader, trimTrailingNewLineIfExists); | |
var lines = result.Split(new[] { Environment.NewLine }, StringSplitOptions.None); | |
int actualRowCount = lines.Length; | |
string actualFirstRow = lines[0]; | |
// ASSERT | |
Assert.AreEqual(expectedRowCount, actualRowCount); | |
Assert.AreEqual(expectedHeader, actualFirstRow); | |
} | |
[TestMethod] | |
public void ToDelimitedText_ReturnsCorrectNumberOfProperties() | |
{ | |
// ARRANGE | |
var itemList = new List<ComplexObject> | |
{ | |
new ComplexObject {Id = 1, Name = "Sid", Active = true} | |
}; | |
const string delimiter = ","; | |
const int expectedPropertyCount = 3; | |
// ACT | |
string result = itemList.ToDelimitedText(delimiter); | |
var lines = result.Split(new[] { Environment.NewLine }, StringSplitOptions.None); | |
var properties = lines.First().Split(delimiter.ToCharArray()); | |
var actualPropertyCount = properties.Length; | |
// ASSERT | |
Assert.AreEqual(expectedPropertyCount, actualPropertyCount); | |
} | |
[TestMethod] | |
public void ToDelimitedText_RemovesTrailingNewLine_WhenSet() | |
{ | |
// ARRANGE | |
var itemList = new List<ComplexObject> | |
{ | |
new ComplexObject {Id = 1, Name = "Sid", Active = true}, | |
new ComplexObject {Id = 2, Name = "James", Active = false}, | |
new ComplexObject {Id = 3, Name = "Ted", Active = true}, | |
}; | |
const string delimiter = ","; | |
const bool includeHeader = false; | |
const bool trimTrailingNewLineIfExists = true; | |
// ACT | |
string result = itemList.ToDelimitedText(delimiter, includeHeader,trimTrailingNewLineIfExists); | |
bool endsWithNewLine = result.EndsWith(Environment.NewLine); | |
// ASSERT | |
Assert.IsFalse(endsWithNewLine); | |
} | |
[TestMethod] | |
public void ToDelimitedText_IncludesTrailingNewLine_WhenNotSet() | |
{ | |
// ARRANGE | |
var itemList = new List<ComplexObject> | |
{ | |
new ComplexObject {Id = 1, Name = "Sid", Active = true}, | |
new ComplexObject {Id = 2, Name = "James", Active = false}, | |
new ComplexObject {Id = 3, Name = "Ted", Active = true}, | |
}; | |
const string delimiter = ","; | |
// ACT | |
string result = itemList.ToDelimitedText(delimiter); | |
bool endsWithNewLine = result.EndsWith(Environment.NewLine); | |
// ASSERT | |
Assert.IsTrue(endsWithNewLine); | |
} | |
#endregion | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment