前言

最近在捣鼓DataTable,弄到了类型转换,既然弄了,那就整个记录。有不足之处,请多多指教。我看了一下目前的转换方式基本上都大差不差,基本上都是通过反射来操作的。本文介绍的两种方式也都是利用反射来完成的。两种方式都写成的通用类,仅供参考。

想法

DataTable

DataTable 是 C# 中常用的一种数据表格类型,它类似于数据库中的表格,可以用来存储和处理数据。DataTable 中的数据可以通过行和列来访问和操作,每行代表一个数据项,每列代表一个属性。

以下是一些 DataTable 的常用属性和方法:

  • Columns:列集合。

  • Rows:行集合。

  • NewRow():创建一个新的 DataRow 对象。

  • Load(DataReader):从一个 DataReader 对象中加载数据到 DataTable。

  • Select(filterExpression, sortExpression):根据指定的筛选条件和排序条件返回满足条件的行集合。

  • Merge(DataTable):合并两个 DataTable,返回一个新的 DataTable。

List

List 是 C# 中常用的一种动态数组类型,它可以用来存储任何类型的数据,可以动态增加或删除元素。List 中的元素可以通过索引来访问和操作。

以下是一些 List 的常用属性和方法:

  • Count:元素数量。

  • Add(item):添加一个元素到 List 的末尾。

  • Insert(index, item):在指定的位置插入一个元素。

  • Remove(item):从 List 中删除一个元素。

  • RemoveAt(index):删除指定位置的元素。

  • Contains(item):判断 List 中是否包含指定的元素。

完整代码

方式一

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
​
using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
​
namespace GCT.TestInterface
{
    public static class DataTableHelper
    {
        /// <summary>
        /// DataTable转成List
        /// </summary>
        public static List<T> ToDataList<T>(this DataTable dt)
        {
            var list = new List<T>();
            //创建一个属性的列表,并赋值
            var plist = new List<PropertyInfo>(typeof(T).GetProperties());
​
            if (dt == null || dt.Rows.Count == 0)
            {
                return null;
            }
​
            foreach (DataRow item in dt.Rows)
            {
                //实例化泛型对象
                T s = Activator.CreateInstance<T>();
​
                //遍历dataTable中的列集合
                for (int i = 0; i < dt.Columns.Count; i++)
                {
                    //获取属性和DataTable的列名称相同的属性(PropertyInfo)
                    PropertyInfo info = plist.Find(p => p.Name == dt.Columns[i].ColumnName);
                    //判断是否存在
                    if (info != null)
                    {
                        try
                        {
                            //判断是否为空
                            if (!Convert.IsDBNull(item[i]))
                            {
                                object v = null;
                                //判断属性是否包含可空
                                if (info.PropertyType.ToString().Contains("System.Nullable"))
                                {
                                    //类型转换
                                    v = Convert.ChangeType(item[i], Nullable.GetUnderlyingType(info.PropertyType));
                                }
                                else
                                {
                                    //类型转换
                                    v = Convert.ChangeType(item[i], info.PropertyType);
                                }
                                //赋值
                                info.SetValue(s, v, null);
                            }
                        }
                        catch (Exception ex)
                        {
                            throw new Exception("字段[" + info.Name + "]转换出错," + ex.Message);
                        }
                    }
                }
                list.Add(s);
            }
            return list;
        }
​
        /// <summary>
        /// DataTable转成实体对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static T ToDataEntity<T>(this DataTable dt)
        {
            T s = Activator.CreateInstance<T>();
            if (dt == null || dt.Rows.Count == 0)
            {
                return default(T);
            }
            var plist = new List<PropertyInfo>(typeof(T).GetProperties());
            for (int i = 0; i < dt.Columns.Count; i++)
            {
                PropertyInfo info = plist.Find(p => p.Name == dt.Columns[i].ColumnName);
                if (info != null)
                {
                    try
                    {
                        if (!Convert.IsDBNull(dt.Rows[0][i]))
                        {
                            object v = null;
                            if (info.PropertyType.ToString().Contains("System.Nullable"))
                            {
                                v = Convert.ChangeType(dt.Rows[0][i], Nullable.GetUnderlyingType(info.PropertyType));
                            }
                            else
                            {
                                v = Convert.ChangeType(dt.Rows[0][i], info.PropertyType);
                            }
                            info.SetValue(s, v, null);
                        }
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("字段[" + info.Name + "]转换出错," + ex.Message);
                    }
                }
            }
            return s;
        }
​
        /// <summary>
        /// List转成DataTable
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="entities">实体集合</param>
        public static DataTable ToDataTable<T>(List<T> entities)
        {
            //判断List的状态
            if (entities == null || entities.Count == 0)
            {
                return null;
            }
            //新建一个DataTable
            var result = new DataTable();
            //获取实体类型数据
            var type = typeof(T);
            //遍历实体类型数据
            foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                //获取属性类型
                var propertyType = property.PropertyType;
                //判断是否存在,是否可为空
                if (propertyType.IsGenericType && (propertyType.GetGenericTypeDefinition() == typeof(Nullable<>)))
                {
                    propertyType = propertyType.GetGenericArguments()[0];
                }
                //添加列
                result.Columns.Add(property.Name, propertyType);
            }
​
            foreach (var entity in entities)
            {
                //创建一个具有相同架构的表格行
                DataRow row = result.NewRow();
​
                foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
                {
                    //填充数据
                    row[property.Name] = property.GetValue(entity) ?? DBNull.Value;
                }
                //添加行
                result.Rows.Add(row);
            }
            return result;
        }
    }
}

方式二

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
​
using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
​
namespace GCT.TestInterface
{
    public static class DataTableHelper
    {
        /// <summary>
        /// 利用反射将Datatable转换为List<T>对象
        /// </summary>
        /// <typeparam name="T">集合</typeparam>
        /// <param name="dt"> datatable对象</param>
        /// <returns></returns>
        public static List<T> ToDataList<T>(this DataTable dt) where T : new()
        {
            //定义集合
            List<T> ts = new List<T>();
​
            //遍历dataTable中的数据行
            foreach (DataRow dr in dt.Rows)
            {
                T t = new T();
                //这里也有两种写法,可以先获取模型的属性数组,也先遍历再获取指定值的属性,看自己喜好采用
                #region 获得此模型的公共属性
                获得此模型的公共属性
                PropertyInfo[] propertys = t.GetType().GetProperties();
​
                //遍历该对象的所有属性
                foreach (PropertyInfo pi in propertys)
                {
                    string tempName = pi.Name;
                    //检查datatable是否包含此列(列名==对象的属性名)
                    //判断此属性是否有setter,这个啥意思呢,就是我们的实体层的{get;set;}如果我们的实体有了set方法,就说明可以赋值!
                    if (!dt.Columns.Contains(tempName) && !pi.CanWrite) continue;
                    object value = dr[tempName];//取值
                    if (value == DBNull.Value) continue;  //如果非空,则赋给对象的属性
                    pi.SetValue(t, ConvertHelper.HackType(value, pi.PropertyType), null);
                }
                #endregion
​
                #region 先遍历再获取指定的
                //遍历dataTable列集合
                foreach (var c in dt.Columns)
                {
                    //读取值
                    object value = dr[c.ToString()];
                    //判断是否存在
                    if (value != DBNull.Value)
                    {
                        //获取指定值的属性
                        var p = t.GetType().GetProperty(c.ToString());
                        if (p != null)
                        {
                            //对象赋值
                            p.SetValue(t, ConvertHelper.ChangeType(value, p.PropertyType), null);
                        }
                    }
                }
                #endregion
                //对象添加到泛型集合中
                ts.Add(t);
            }
            return ts;
        }
​
        /// <summary>
        /// DataTable转成实体对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dt"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static T ToDataEntity<T>(this DataTable dt) where T : new()
        {
            if (dt.Rows.Count > 1)
            {
                throw new Exception("");
            }
            //遍历行
            foreach (DataRow dr in dt.Rows)
            {
                T t = new T();
                //遍历列
                foreach (var c in dt.Columns)
                {
                    //获取指定值
                    object value = dr[c.ToString()];
                    if (value != DBNull.Value)
                    {
                        //获取公共属性
                        var p = t.GetType().GetProperty(c.ToString());
                        if (p != null)
                        {
                            p.SetValue(t, ConvertHelper.ChangeType(value, p.PropertyType), null);
                        }
                    }
                }
                return t;
            }
            return default(T);
        }
    }
}

  • 类型转换

用方式二有时候会报类型转换的错误,因此也提供了两种转换方式

    /// <summary>
    /// 类型转换
    /// </summary>
    public static class ConvertHelper
    {
        #region 方式一
​
        public static object HackType(object value, Type conversionType)
        {
            if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
            {
                if (value == null)
                    return null;
                System.ComponentModel.NullableConverter nullableConverter = new System.ComponentModel.NullableConverter(conversionType);
                conversionType = nullableConverter.UnderlyingType;
            }
            return Convert.ChangeType(value, conversionType);
        }
​
        #endregion 方式一
​
​
​
        #region 方式二
​
        public static object ChangeType(object obj, Type conversionType)
        {
            return ChangeType(obj, conversionType, System.Threading.Thread.CurrentThread.CurrentCulture);
        }
​
        public static object ChangeType(object obj, Type conversionType, IFormatProvider provider)
        {
            #region Nullable
​
            Type nullableType = Nullable.GetUnderlyingType(conversionType);
            if (nullableType != null)
            {
                if (obj == null)
                {
                    return null;
                }
                return Convert.ChangeType(obj, nullableType, provider);
            }
​
            #endregion Nullable
​
            if (typeof(Enum).IsAssignableFrom(conversionType))
            {
                return Enum.Parse(conversionType, obj.ToString());
            }
            return Convert.ChangeType(obj, conversionType, provider);
        }
​
        #endregion 方式二
    }

方法三

// 将 DataTable 转换为 List
public static List<Dictionary<string, object>> DataTableToList(DataTable dt)
{
    List<Dictionary<string, object>> list = new List<Dictionary<string, object>>();
    foreach (DataRow row in dt.Rows)
    {
        Dictionary<string, object> dict = new Dictionary<string, object>();
        foreach (DataColumn col in dt.Columns)
        {
            dict[col.ColumnName] = row[col];
        }
        list.Add(dict);
    }
    return list;
}
​
// 将 List 转换为 DataTable
public static DataTable ListToDataTable(List<Dictionary<string, object>> list)
{
    DataTable dt = new DataTable();
    if (list.Count > 0)
    {
        foreach (string columnName in list[0].Keys)
        {
            dt.Columns.Add(columnName);
        }
    }
    foreach (Dictionary<string, object> dict in list)
    {
        DataRow row = dt.NewRow();
        foreach (string columnName in dict.Keys)
        {
            row[columnName] = dict[columnName];
        }
        dt.Rows.Add(row);
    }
    return dt;
}

这里的 DataTableToList 方法将 DataTable 转换为一个 List,其中每个元素都是一个 Dictionary,表示 DataTable 的一行数据。每个 Dictionary 的键是 DataTable 的列名,值是该行对应列的值。

ListToDataTable 方法则将 List 转换为 DataTable,需要注意的是,List 中的每个元素都必须具有相同的键集合,否则无法创建 DataTable。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐