Imports System.Runtime.CompilerServices Imports System.Reflection Imports System.Data Namespace Extensiones Public Module IEnumerableExtensions Public Function CopyToDataTable(Of T)(ByVal source As IEnumerable(Of T)) As DataTable Return New ObjectShredder(Of T)().Shred(source, Nothing, Nothing) End Function Public Function CopyToDataTable(Of T)(ByVal source As IEnumerable(Of T), ByVal table As DataTable, ByVal options As LoadOption?) As DataTable Return New ObjectShredder(Of T)().Shred(source, table, options) End Function End Module End Namespace Public Class ObjectShredder(Of T) Private _fi As FieldInfo() Private _pi As PropertyInfo() Private _ordinalMap As Dictionary(Of String, Integer) Private _type As Type Public Sub New() _type = GetType(T) _fi = _type.GetFields() _pi = _type.GetProperties.Where(Function(x) Not (x.PropertyType.Name.Contains("EntityReference") OrElse x.PropertyType.Name.Contains("EntityCollection") OrElse x.PropertyType.Name.Contains("EntityState") OrElse x.PropertyType.Name.Contains("EntityKey") OrElse x.PropertyType.BaseType.Name = "EntityObject")).ToArray _ordinalMap = New Dictionary(Of String, Integer)() End Sub Public Function Shred(ByVal source As IEnumerable(Of T), ByVal table As DataTable, ByVal options As LoadOption?) As DataTable If GetType(T).IsPrimitive Then Return ShredPrimitive(source, table, options) End If If table Is Nothing Then table = New DataTable(GetType(T).Name) End If table = ExtendTable(table, GetType(T)) table.BeginLoadData() Using e As IEnumerator(Of T) = source.GetEnumerator() While e.MoveNext() If options IsNot Nothing Then table.LoadDataRow(ShredObject(table, e.Current), CType(options, LoadOption)) Else table.LoadDataRow(ShredObject(table, e.Current), True) End If End While End Using table.EndLoadData() Return table End Function Public Function ShredPrimitive(ByVal source As IEnumerable(Of T), ByVal table As DataTable, ByVal options As LoadOption?) As DataTable If table Is Nothing Then table = New DataTable(GetType(T).Name) End If If Not table.Columns.Contains("Value") Then table.Columns.Add("Value", GetType(T)) End If table.BeginLoadData() Using e As IEnumerator(Of T) = source.GetEnumerator() Dim values As Object() = New Object(table.Columns.Count - 1) {} While e.MoveNext() values(table.Columns("Value").Ordinal) = e.Current If options IsNot Nothing Then table.LoadDataRow(values, CType(options, LoadOption)) Else table.LoadDataRow(values, True) End If End While End Using table.EndLoadData() Return table End Function Public Function ExtendTable(ByVal table As DataTable, ByVal type As Type) As DataTable For Each f As FieldInfo In type.GetFields() If Not _ordinalMap.ContainsKey(f.Name) Then Dim dc As DataColumn = If(table.Columns.Contains(f.Name), table.Columns(f.Name), table.Columns.Add(f.Name, f.FieldType)) _ordinalMap.Add(f.Name, dc.Ordinal) End If Next Dim Propiedades = type.GetProperties.Where(Function(x) Not (x.PropertyType.Name.Contains("EntityReference") OrElse x.PropertyType.Name.Contains("EntityCollection") OrElse x.PropertyType.Name.Contains("EntityState") OrElse x.PropertyType.Name.Contains("EntityKey") OrElse x.PropertyType.BaseType.Name = "EntityObject")) For Each p As PropertyInfo In Propiedades If Not _ordinalMap.ContainsKey(p.Name) Then Dim propiedad = p.PropertyType If propiedad Is GetType(Integer?) Then propiedad = GetType(Integer) ElseIf propiedad Is GetType(Double?) Then propiedad = GetType(Double) ElseIf propiedad Is GetType(Long?) Then propiedad = GetType(Long) ElseIf propiedad Is GetType(Boolean?) Then propiedad = GetType(Boolean) ElseIf propiedad Is GetType(DateTime?) Then propiedad = GetType(DateTime) ElseIf propiedad Is GetType(Date?) Then propiedad = GetType(Date) End If Dim dc As DataColumn = If(table.Columns.Contains(p.Name), table.Columns(p.Name), table.Columns.Add(p.Name, propiedad)) _ordinalMap.Add(p.Name, dc.Ordinal) End If Next Return table End Function Public Function ShredObject(ByVal table As DataTable, ByVal instance As T) As Object() Dim fi As FieldInfo() = _fi Dim pi As PropertyInfo() = _pi If instance.[GetType]() <> GetType(T) Then ExtendTable(table, instance.[GetType]()) fi = instance.[GetType]().GetFields() pi = instance.[GetType]().GetProperties.Where(Function(x) Not (x.PropertyType.Name.Contains("EntityReference") OrElse x.PropertyType.Name.Contains("EntityCollection") OrElse x.PropertyType.Name.Contains("EntityState") OrElse x.PropertyType.Name.Contains("EntityKey") OrElse x.PropertyType.BaseType.Name = "EntityObject")).ToArray End If Dim values As Object() = New Object(table.Columns.Count - 1) {} For Each f As FieldInfo In fi values(_ordinalMap(f.Name)) = f.GetValue(instance) Next For Each p As PropertyInfo In pi values(_ordinalMap(p.Name)) = p.GetValue(instance, Nothing) Next Return values End Function End Class