我们在项目中经常会使用到 List 转为 DataTable
方法一. 通过 扩展方法的方式,写一个IList接口的扩展方法
using System;
using System.Collections.Generic;
using System.Data;
using System.ComponentModel;
namespace DocumentSearch
{
public static class DataTableExtensions
{
public static DataTable ToDataTable<T>(this IList<T> data)
{
PropertyDescriptorCollection properties =
TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
foreach (PropertyDescriptor prop in properties)
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
foreach (T item in data)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
table.Rows.Add(row);
}
return table;
}
}
}
调用时:
var users = dbContext.Users.ToList().ToDataTable();
或
var users = dbContext.Users.ToListAsync().Result.ToDataTable();
注意:用异步转为list,则要等 有result后再转为 datatable.
方法二.写一个自定义的类
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Reflection;
using System.ComponentModel;
namespace DotNet.Utilities
{
/// <summary>
/// IList 公共帮助类
/// </summary>
public class IListHelper
{
/// <summary>
/// IList如何转成List<T>
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <returns></returns>
public static List<T> IListToList<T>(IList list)
{
T[] array = new T[list.Count];
list.CopyTo(array, 0);
return new List<T>(array);
}
/// <summary>
/// Convert a List{T} to a DataTable.
/// </summary>
public static DataTable ToDataTable<T>(List<T> items)
{
var tb = new DataTable(typeof(T).Name);
PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo prop in props)
{
Type t = GetCoreType(prop.PropertyType);
tb.Columns.Add(prop.Name, t);
}
foreach (T item in items)
{
var values = new object[props.Length];
for (int i = 0; i < props.Length; i++)
{
values[i] = props[i].GetValue(item, null);
}
tb.Rows.Add(values);
}
return tb;
}
/// <summary>
/// Determine of specified type is nullable
/// </summary>
public static bool IsNullable(Type t)
{
return !t.IsValueType || (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>));
}
/// <summary>
/// Return underlying type if type is Nullable otherwise return the type
/// </summary>
public static Type GetCoreType(Type t)
{
if (t != null && IsNullable(t))
{
if (!t.IsValueType)
{
return t;
}
else
{
return Nullable.GetUnderlyingType(t);
}
}
else
{
return t;
}
}
public static DataTable ToDataTable<T>(IList<T> data)
{
PropertyDescriptorCollection properties =
TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
foreach (PropertyDescriptor prop in properties)
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
foreach (T item in data)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
table.Rows.Add(row);
}
return table;
}
}
}
VB:
Imports System.Data
Imports System.Collections
Imports System.Reflection
' <summary>
' IList 公共帮助类
' </summary>
Public Class IListHelper
''' <summary>
''' Convert a DataGridView to DataTable
''' </summary>
''' <param name="dgv"></param>
''' <returns></returns>
Public Function ToDataTable(ByVal dgv As DataGridView) As DataTable
Dim tb = New DataTable(dgv.Name)
'Add table column
For Each col In dgv.Columns.OfType(Of DataGridViewColumn)
tb.Columns.Add(col.HeaderText)
Next
'Content
For Each dgvrow In dgv.Rows.OfType(Of DataGridViewRow)
Dim datarow = tb.NewRow()
For Each col In dgv.Columns.OfType(Of DataGridViewColumn)
datarow(col.Name) = Convert.ToString(dgvrow.Cells(col.Name).Value)
Next
tb.Rows.Add(datarow)
Next
Return tb
End Function
' <summary>
' Convert a List{T} to a DataTable.
' </summary>
Public Function ToDataTable(Of T)(ByVal items As List(Of T)) As DataTable
Dim tb = New DataTable(GetType(T).Name)
Dim props As PropertyInfo() = GetType(T).GetProperties(BindingFlags.Public OrElse BindingFlags.Instance)
For Each prop As PropertyInfo In props
'Type T = GetCoreType(prop.PropertyType)
tb.Columns.Add(prop.Name, GetCoreType(prop.PropertyType))
Next
For Each item In items
Dim values(props.Length - 1) As Object
For i = 0 To props.Length - 1
values(i) = props(i).GetValue(item)
Next
tb.Rows.Add(values)
Next
Return tb
End Function
' <summary>
' Determine of specified type Is nullable
' </summary>
Public Function IsNullable(ByVal t As Type) As Boolean
Return Not t.IsValueType 'Or (t.IsGenericType And t.GetGenericTypeDefinition() = GetType(Nullable()))
End Function
' <summary>
' Return underlying type if type Is Nullable otherwise return the type
' </summary>
Public Function GetCoreType(ByVal t As Type) As Type
If t <> Nothing And IsNullable(t) Then
If (Not t.IsValueType) Then
Return t
Else
Return Nullable.GetUnderlyingType(t)
End If
Else
Return t
End If
End Function
End Class