c#中实体类和DataTable之间相互转换,实体反射动态遍历列详解

在实际项目中,经常会用到数据之间的相互转换,序列化和反序列化就是常见场景。这里我们只简单聊聊实体类和DataTable之间的相互转换,可以用于不同业务场景使用。

目录
1、DataTable转Model
2、Model转DataTable
3、反射概念
3.1、Type 类型
3.2、Assembly 程序集
3.3、MemberInfo 成员信息
3.4、PropertyInfo 属性信息
4、常见问题
1、DataTable转Model
要将C# DataTable 转换为 Model 实体类,你可以使用反射来获取 DataTable 的列和值,并通过实例化 Model 类来赋值。

1)将 DataTable 转换为 Model 类

示例代码
using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;

public static class DataTableExtensions
{
    public static List<T> ToList<T>(this DataTable dataTable) where T : class, new()
    {
        List<T> list = new List<T>();

        foreach (DataRow row in dataTable.Rows)
        {
            T obj = new T();

            foreach (DataColumn col in dataTable.Columns)
            {
                PropertyInfo property = typeof(T).GetProperty(col.ColumnName);
                if (property != null && row[col] != DBNull.Value)
                {
                    property.SetValue(obj, row[col]);
                }
            }

            list.Add(obj);
        }

        return list;
    }
}

2) DataTable 转换为指定的 Model 实体类

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

DataTable dataTable = new DataTable();
dataTable.Columns.Add("Id", typeof(int));
dataTable.Columns.Add("Name", typeof(string));
dataTable.Columns.Add("Age", typeof(int));

dataTable.Rows.Add(1, "John", 25);
dataTable.Rows.Add(2, "Jane", 30);
dataTable.Rows.Add(3, "Mike", 40);

List<Person> persons = dataTable.ToList<Person>();

运行效果

上述代码将会创建一个包含了 DataTable 数据的 Person 实体类的 List。每个列的数据将会分配给 Person 对应的属性。
请注意,上述示例中的 Person 类只是一个示例,你可以根据自己的需求创建自定义的实体类,并根据 DataTable 的列名称和类型匹配属性。另外,还需确保对应的属性存在,并且列的值类型与属性类型兼容。

2、Model转DataTable
要将C# 实体通过反射转换为 DataTable,可以使用System.Reflection命名空间中的类来访问实体的属性和值,并将其添加到 DataTable 中。
1)使用反射来转换实体为 DataTable

using System;
using System.Data;
using System.Reflection;

public static class EntityExtensions
{
    public static DataTable ToDataTable<T>(this T[] entities)
    {
        DataTable dataTable = new DataTable(typeof(T).Name);

        PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);

        foreach (PropertyInfo propInfo in properties)
        {
            dataTable.Columns.Add(propInfo.Name, propInfo.PropertyType);
        }

        foreach (T entity in entities)
        {
            object[] values = new object[properties.Length];
            for (int i = 0; i < properties.Length; i++)
            {
                values[i] = properties[i].GetValue(entity);
            }

            dataTable.Rows.Add(values);
        }

        return dataTable;
    }
}

2)将任何实体数组转换为 DataTable

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

Person[] persons = new Person[]
{
    new Person { Id = 1, Name = "John", Age = 25 },
    new Person { Id = 2, Name = "Jane", Age = 30 },
    new Person { Id = 3, Name = "Mike", Age = 40 }
};

DataTable dataTable = persons.ToDataTable();

运行效果

上述代码将会创建一个包含了Person实体数组数据的 DataTable。每个属性都会成为该 DataTable 的列,并且每个实体实例将会形成 DataTable 的一行。
请注意,上述示例中的实体类 Person 只是一个示例,你可以根据自己的需求创建自定义的实体类,并使用相应的属性和类型。

3、反射概念
C# 的反射是指在运行时获取、检查和操作程序集、类型、成员(如字段、属性、方法等)的能力。反射提供了一组类和方法,可以在运行时动态地获取程序集和类型的信息,并使用这些信息来创建对象、调用方法、访问属性等。

以下是一些关键概念和用途:

3.1、Type 类型
Type 类型是反射的核心,它表示在运行时加载的类型。Type 类型提供了获取类型信息的方法和属性,如名称、基类、实现的接口、属性、方法、字段等。利用 Type 类型,你可以动态地获取和操作类型的信息。

3.2、Assembly 程序集
Assembly 类型表示一个程序集,它是一个逻辑单元,包含可执行文件、动态链接库或代码的容器。通过反射,你可以加载和检查程序集的信息,包括类型、成员、属性等。可以使用 Assembly 类型来加载程序集、获取程序集中的类型、创建对象等。

3.3、MemberInfo 成员信息
MemberInfo 类型表示类型的成员,如字段、属性、方法、事件等。它提供了获取成员的名称、类型、访问修饰符等信息的方法。

3.4、PropertyInfo 属性信息
PropertyInfo 类型表示类型的属性,它提供了获取和设置属性值的方法和属性。

通过反射,你可以实现许多动态和灵活的功能,如:

动态创建对象和调用方法:在运行时根据类型信息动态创建对象,调用对象的方法。
动态访问和修改属性值:在运行时获取对象的属性信息,并动态修改属性值。
获取和检查类型信息:在运行时获取类型的信息,如名称、基类、实现的接口、成员等。
加载和使用外部程序集:动态加载和使用外部程序集,以便在运行时访问和操作其中的类型和成员。
编写通用代码:使用反射可以编写通用、灵活的代码,以适应不同类型和成员的情况。
需要注意的是,反射在一定程度上会带来性能上的损失,因为它需要在运行时进行类型信息的获取和检查。因此,在使用反射时需要权衡性能和灵活性之间的关系,并注意避免不必要的反射操作。

4、常见问题
1)当实体类有成员定义成可空类型时,如果不做处理,那么会报错


2)在 DataSet 中,确实不支持直接使用 System.Nullable<> 类型。

如果你想在 DataTable 的列中使用可为空的类型,你可以使用 System.Object 类型,并在需要时将其设置为 DBNull.Value 来表示空值。

DataTable dataTable = new DataTable();

// 添加可为空的整数列
DataColumn nullableIntColumn = new DataColumn("NullableInt", typeof(object));
dataTable.Columns.Add(nullableIntColumn);

// 添加可为空的字符串列
DataColumn nullableStringColumn = new DataColumn("NullableString", typeof(object));
dataTable.Columns.Add(nullableStringColumn);

在上述代码中,我们创建了一个 DataTable 对象 dataTable,并添加了两个列:NullableInt 和 NullableString。

为了将列定义为可为空类型,我们使用了 typeof(object) 来定义列的类型,这样可以允许任意的对象,并且可以在需要时将其设置为 DBNull.Value 来表示空值。

3)在 DataTable 的列中存储可为空的值,例如:

DataRow row = dataTable.NewRow();
row["NullableInt"] = DBNull.Value; // 可空整数为空,使用 DBNull.Value 表示
row["NullableString"] = DBNull.Value; // 可空字符串为空,使用 DBNull.Value 表示
dataTable.Rows.Add(row);

通过这种方式,你可以在 DataTable 的列中处理可为空的类型,并使用 DBNull.Value 来表示空值。请注意,在读取和处理数据时,你需要检查某个列的值是否为 DBNull.Value,以判断是否为空

  • 13
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于"c"这个字符,它在计算机科学有着重要的地位。 首先,它是一种编程语言。C语言是一种广泛使用的、高效的程序设计语言。它具有简单、灵活、高效的特点,能够进行底层的内存操作和指针运算。C语言被广泛用于系统开发、嵌入式系统、操作系统等领域。 其次,它是一种数据类型。在C语言,"c"可以表示字符类型。字符类型是一种用于存储单个字符的数据类型,它能够存储ASCII码或Unicode码的字符。在C语言,我们可以使用字符数据类型来处理文本数据、实现输入输出等功能。 另外,"c"还代表了指针。指针是C语言一个重要的概念,它存储了一个变量或对象的内存地址。通过使用指针,我们可以实现对内存的直接访问和操作。指针在C语言具有重要的作用,它使得我们可以更灵活地管理内存,并实现一些高级的数据结构和算法。 此外,"c"还可以代表C标准库。C标准库是C语言的一个重要组成部分,它包含了大量的函数和常量,能够实现各种功能,例如输入输出、数学计算、内存管理等。C标准库提供了一些常用的函数供开发人员使用,能够简化程序的开发过程。 总的来说,"c"在计算机科学有着重要的地位。它代表了一种编程语言、一种数据类型、一种指针操作以及C标准库。掌握"C",能够帮助我们进行程序设计、内存管理和算法实现等方面的工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值