I guess below code will works for you.
I could handle it without custom attribute.
Code
public static class Extensions
{
public static string Piped<T>(this IList<T> source)
{
var sb = new StringBuilder();
var pInfo = typeof(T).GetProperties().Where(x => x.GetCustomAttributes<DisplayNameAttribute>().Any());
bool first = true;
foreach (var i in source)
{
if (first)
{
//foreach (var h in pInfo.Select(x => x.GetCustomAttribute<DisplayNameAttribute>().DisplayName))
//{
// sb.Append(h);
// sb.Append('|');
//}
sb.Append(string.Join('|', pInfo.Select(x => x.GetCustomAttribute<DisplayNameAttribute>().DisplayName)));
sb.Append(Environment.NewLine);
first = false;
}
foreach (var y in i.GetType().GetProperties().Where(x => x.GetCustomAttributes<DisplayNameAttribute>().Any()))
{
sb.Append(i.GetType().GetProperty(y.Name).GetValue(i, null).ToString());
sb.Append('|');
}
sb.Append(Environment.NewLine);
}
return sb.ToString();
}
}
Usage
public partial class ExportData
{
[DisplayName("Test Code 123")]
public string Code { get; set; }
[DisplayName("Test Name 123")]
public string Name { get; set; }
[DisplayName("whatever you want")]
public string Address { get; set; }
}
static void Main(string[] args)
{
var lst = new List<ExportData>() {
new ExportData{ Code = "c1", Name ="n1", Address = "a1" },
new ExportData{ Code = "c2", Name ="n2", Address = "a2" },
new ExportData{ Code = "c3", Name ="n3", Address = "a3" },
};
Console.WriteLine(lst.Piped());
Console.ReadKey();
}
Result
Test Code 123|Test Name 123|Whatever you want|
c1|n1|a1|
c2|n2|a2|
c3|n3|a3|