Skip to content

Instantly share code, notes, and snippets.

@qyen
Created June 4, 2018 01:29
Show Gist options
  • Save qyen/dc847a5c4d3719abc4ad314e1dc6fdb8 to your computer and use it in GitHub Desktop.
Save qyen/dc847a5c4d3719abc4ad314e1dc6fdb8 to your computer and use it in GitHub Desktop.
Convert IEnumerable<T> to DataTable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace qyen.toos {
public static class ExtensionForDataTable {
private const string FieldConnectorChar = "_";
/// <summary>
/// Convert IEnumerable<T> To System.Data.DataTable
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="datas"></param>
/// <param name="expandPropertyOptions"></param>
/// <returns></returns>
public static System.Data.DataTable ToDataTable<T>(this IEnumerable<T> datas, ExpandPropertyOptions expandPropertyOptions = null) {
return datas.ToDataTable(expandPropertyOptions != null, expandPropertyOptions);
}
/// <summary>
/// Convert IEnumerable<T> To System.Data.DataTable
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="datas"></param>
/// <param name="ExpandNonPrimitiveClass"></param>
/// <param name="expandPropertyOptions"></param>
/// <returns></returns>
public static System.Data.DataTable ToDataTable<T>(this IEnumerable<T> datas, bool ExpandNonPrimitiveClass = false, ExpandPropertyOptions expandPropertyOptions = null) {
var baseType = typeof(T);
var hlist = baseType.BuildPropertyList(ExpandNonPrimitiveClass);
var res = new System.Data.DataTable();
//build DataTable Schema
foreach (var prop in hlist.Where(x => !hlist.Any(y => y.parent == x))) {
res.Columns.Add(new System.Data.DataColumn() {
ColumnName = prop.PropertyName,
DataType = NonNullable(prop.Property.PropertyType),
});
}
//Add Contents
foreach (var data in datas) {
var row = res.NewRow();
foreach (var prop in hlist.Where(x => !hlist.Any(y => y.parent == x))) {
var d = prop.GetHierarchicalValue(data);
if (d != null)
row[prop.PropertyName] = d;
}
res.Rows.Add(row);
}
return res;
}
/// <summary>
/// Build hierarchical Property Info
/// </summary>
/// <param name="baseType"></param>
/// <param name="ExpandNonPrimitiveClass"></param>
/// <param name="expandPropertyOptions"></param>
/// <param name="parent"></param>
/// <returns></returns>
internal static IEnumerable<HierarchyPropertyNode> BuildPropertyList(this Type baseType, bool ExpandNonPrimitiveClass = false, ExpandPropertyOptions expandPropertyOptions = null, HierarchyPropertyNode parent = null) {
if (expandPropertyOptions == null) {
expandPropertyOptions = new ExpandPropertyOptions();
}
var props = baseType.GetProperties();
var res = new List<HierarchyPropertyNode>();
foreach (var prop in props) {
var hpn = new HierarchyPropertyNode() {
parent = parent,
Property = prop,
};
res.Add(hpn);
if (ExpandNonPrimitiveClass
&& prop.PropertyType.CanExpand()
&& expandPropertyOptions.CanExpand(hpn)) {
res.AddRange(prop.PropertyType.BuildPropertyList(ExpandNonPrimitiveClass, expandPropertyOptions, hpn));
}
}
return res;
}
/// <summary>
/// Option settings
/// </summary>
public class ExpandPropertyOptions {
public bool ExpandCircularReference { get; set; } = false;
public int MaxReferenceLevel { get; set; } = 3;
public IList<string> IncludeProperties { get; private set; } = new List<string>();
public ExpandPropertyOptions Include(string Property) {
if (!string.IsNullOrEmpty(Property))
IncludeProperties.Add(Property.Replace(".", "_"));
return this;
}
internal bool CanExpand(HierarchyPropertyNode hpn) {
bool result = true;
if (hpn.Level >= MaxReferenceLevel)
result = false;
if (!ExpandCircularReference && hpn.IsCircularReference)
result = false;
if (IncludeProperties.Any() && !IncludeProperties.Contains(hpn.PropertyName))
result = false;
return result;
}
}
/// <summary>
/// Hierarchical Property Info
/// </summary>
/// <remarks>
/// parent : key
/// </remarks>
internal class HierarchyPropertyNode {
public HierarchyPropertyNode parent { get; set; }
public PropertyInfo Property { get; set; }
public string PropertyName {
get {
return string.Join(FieldConnectorChar, this.Hierarchy.Select(x => x.Property.Name));
}
}
private IEnumerable<HierarchyPropertyNode> Parents {
get {
var current = this.parent;
var res = new List<HierarchyPropertyNode>();
while (current != null) {
res.Add(current);
current = current.parent;
}
res.Reverse();
return res;
}
}
private IEnumerable<HierarchyPropertyNode> Hierarchy {
get {
var list = Parents.ToList();
list.Add(this);
return list;
}
}
internal int Level {
get {
return Hierarchy.Count();
}
}
internal bool IsCircularReference {
get {
return ParentHasSameType(Property.PropertyType);
}
}
private bool ParentHasSameType(Type type) {
return Parents.Any(x => x.Property.PropertyType == type);
}
/// <summary>
/// Get value from root object
/// </summary>
/// <param name="root"></param>
/// <returns>if any parent gets null,return null </returns>
internal object GetHierarchicalValue(object root) {
object value = root;
foreach (var h in Hierarchy) {
try {
value = h.Property.GetValue(value, null);
} catch {
return null;
}
}
return value;
}
}
/// <summary>
/// If Type is Nullable<T> return T,else return t
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
private static Type NonNullable(Type t) {
return Nullable.GetUnderlyingType(t) ?? t;
}
/// <summary>
/// check t is Nullable
/// </summary>
/// <param name="t"></param>
/// <returns></returns>
private static bool IsNullable(Type t) {
return Nullable.GetUnderlyingType(t) != null;
}
/// <summary>
///
/// </summary>
private static Type[] ExcludeExpands = new Type[] { typeof(DateTime), typeof(string), typeof(decimal) };
/// <summary>
/// Check objClass can expand
/// </summary>
/// <param name="objClass"></param>
/// <returns></returns>
private static bool CanExpand(this Type objClass) {
return !objClass.IsPrimitive
&& !ExcludeExpands.Contains(objClass)
&& !IsNullable(objClass)
&& !objClass.GetInterfaces().Any(t => t == typeof(IEnumerable<>));
}
}
}
@qyen
Copy link
Author

qyen commented Jun 4, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment