Last active
February 15, 2018 10:22
-
-
Save wipiano/787b600ab8af86951fb9b5e5236f982b to your computer and use it in GitHub Desktop.
convert object to csv
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 System.Reflection; | |
namespace ObjectToCsv | |
{ | |
internal class Program | |
{ | |
public static void Main(string[] args) | |
{ | |
var rows = new[] | |
{ | |
new SampleObj1() | |
{ | |
Name = "taro", | |
Age = 12, | |
Memo = "memomoe", | |
Score = 55.232, | |
}, | |
new SampleObj1() | |
{ | |
Name = "hanako", | |
Age = 24, | |
Memo = "hanakomemo", | |
Score = 80, | |
}, | |
}; | |
foreach (var row in CsvFormatter<SampleObj1>.ToCsv(rows)) | |
{ | |
Console.WriteLine(row); | |
} | |
} | |
} | |
public sealed class SampleObj1 | |
{ | |
public string Name { get; set; } | |
[Title("age")] | |
public int Age { get; set; } | |
[Ignore] | |
public string Memo { get; set; } | |
[Title("score")] | |
[Format("##.00")] | |
public double Score { get; set; } | |
} | |
public class CsvFormatter<T> | |
{ | |
private static readonly CsvFormatter<T> Instance = new CsvFormatter<T>(); | |
private readonly IReadOnlyList<CsvField> _fields; | |
private readonly string _title; | |
private CsvFormatter() | |
{ | |
_fields = CsvField.Create<T>(); | |
_title = string.Join(",", _fields.Where(f => !f.Ignored).Select(f => f.GetCsvTitle())); | |
} | |
public static string GetTitle() => Instance._title; | |
public static string ToCsvRow(T obj) => string.Join(",", Instance._fields.Where(f => !f.Ignored).Select(f => f.GetCsvString(obj))); | |
public static IEnumerable<string> ToCsv(IEnumerable<T> objs) | |
{ | |
yield return GetTitle(); | |
foreach (var obj in objs) | |
{ | |
yield return ToCsvRow(obj); | |
} | |
} | |
} | |
internal sealed class CsvField | |
{ | |
public string Name { get; } | |
public string Format { get; } | |
public bool Ignored { get; } | |
public PropertyInfo PropInfo { get; } | |
private static readonly Dictionary<string, string> s_escapeExpressions = new Dictionary<string, string>() | |
{ | |
{"\\", "\\\\"}, | |
{"\"", "\\\""} | |
}; | |
public CsvField(string name, string format, bool ignored, PropertyInfo propertyInfo) | |
{ | |
Name = name; | |
Format = format; | |
Ignored = ignored; | |
PropInfo = propertyInfo; | |
} | |
public string GetCsvString(object instance) | |
{ | |
string ToCsvString(string s) | |
{ | |
foreach (var e in s_escapeExpressions) | |
{ | |
s = s.Replace(e.Key, e.Value); | |
} | |
return $@"""{s}""" ?? string.Empty; | |
} | |
object value = PropInfo.GetValue(instance); | |
if (value == null) | |
{ | |
return string.Empty; | |
} | |
return ToCsvString(string.IsNullOrEmpty(Format) ? value.ToString() : string.Format($"{{0:{Format}}}", PropInfo.GetValue(instance))); | |
} | |
public string GetCsvTitle() => Name; | |
public static CsvField[] Create<T>() | |
{ | |
return typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.Public) | |
.Select(info => | |
{ | |
string title = (Attribute.GetCustomAttribute(info, typeof(TitleAttribute)) as TitleAttribute)?.Title ?? info.Name; | |
string format = (Attribute.GetCustomAttribute(info, typeof(FormatAttribute)) as FormatAttribute)?.Format; | |
bool ignore = (Attribute.GetCustomAttribute(info, typeof(IgnoreAttribute)) as IgnoreAttribute) != null; | |
return new CsvField(title, format, ignore, info); | |
}) | |
.ToArray(); | |
} | |
} | |
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] | |
public class TitleAttribute : Attribute | |
{ | |
public string Title { get; } | |
public TitleAttribute(string title) | |
{ | |
Title = title; | |
} | |
} | |
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] | |
public class FormatAttribute : Attribute | |
{ | |
public string Format { get; } | |
public FormatAttribute(string format) | |
{ | |
Format = format; | |
} | |
} | |
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] | |
public class IgnoreAttribute : Attribute | |
{ | |
public IgnoreAttribute() | |
{ | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment