Created
June 4, 2018 01:29
-
-
Save qyen/dc847a5c4d3719abc4ad314e1dc6fdb8 to your computer and use it in GitHub Desktop.
Convert IEnumerable<T> to DataTable
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; | |
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<>)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
howtouse