Lbxy.ListTableBridge 1.0.2

dotnet add package Lbxy.ListTableBridge --version 1.0.2
                    
NuGet\Install-Package Lbxy.ListTableBridge -Version 1.0.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Lbxy.ListTableBridge" Version="1.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Lbxy.ListTableBridge" Version="1.0.2" />
                    
Directory.Packages.props
<PackageReference Include="Lbxy.ListTableBridge" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Lbxy.ListTableBridge --version 1.0.2
                    
#r "nuget: Lbxy.ListTableBridge, 1.0.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Lbxy.ListTableBridge@1.0.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Lbxy.ListTableBridge&version=1.0.2
                    
Install as a Cake Addin
#tool nuget:?package=Lbxy.ListTableBridge&version=1.0.2
                    
Install as a Cake Tool

ListTableBridge

高性能、强类型的 DataTable ↔ List<T> 双向转换工具库
支持基于特性(XafDisplayName / DisplayName / Display)的列名映射、丰富的数据类型转换以及枚举特性解析,适用于 DevExpress XAF 等场景下的实体与 DataTable 交互。


特性概览

  • 🔁 双向转换

    • List<T> → DataTable
    • DataTable → List<T>
  • 🏷 特性驱动的列名映射(属性级)

    • 优先级:XafDisplayName > DisplayName > Display > 属性原始名称
    • 自动处理属性上的显示名特性(无需引用 DevExpress 程序集,只依赖运行时已有特性)
  • 🧩 丰富的数据类型支持

    • 基础类型:int, long, short, byte, float, double, decimal, bool, char, string, DateTime
    • 可空类型:int?, double?, decimal?
    • 枚举类型:支持字符串与数值双向转换
    • 特殊类型:Guid, DateTimeOffset, TimeSpan
    • 集合/复杂对象(通过序列化等策略封装在测试中验证)
  • 🧠 枚举元素特性解析(可控开关)

    • 支持从枚举元素上的 XafDisplayName / DisplayName / Display 中读取显示名
    • 支持从显示名或名称反向解析为枚举值
    • 通过 enableElementFeatureReading 参数控制是否开启,默认 false 以保持向后兼容性
  • 🚀 性能优化

    • 基于表达式树与缓存的反射访问(PropertyInfo → Getter/Setter 委托)
    • 类型元数据缓存,避免重复反射
    • 测试中对 10,000 条数据转换的性能进行了校验
  • 测试完备

    • 使用 xUnit 单元测试
    • 覆盖基础类型、数值子类型、可空组合、枚举特性、字符串边界等多种场景

安装

从 NuGet 安装:

dotnet add package ListTableBridge

或在 .csproj 中添加:

<ItemGroup>
  <PackageReference Include="ListTableBridge" Version="1.0.0" />
</ItemGroup>

目标框架支持:

  • .NET Framework 4.5+
  • .NET Standard 2.0+

快速开始

1. List<T> → DataTable(静态方法)

using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using DevExpress.Persistent.Base; // 示例,实际由你的项目提供
using ListTableBridge;

public class Customer
{
    [XafDisplayName("客户编号")]
    public int Id { get; set; }

    [DisplayName("客户名称")]
    public string Name { get; set; }

    [Display(Name = "状态")]
    public CustomerStatus Status { get; set; }
}

public enum CustomerStatus
{
    [XafDisplayName("启用")]
    Active = 1,

    [XafDisplayName("停用")]
    Inactive = 2
}

var customers = new List<Customer>
{
    new Customer { Id = 1, Name = "张三", Status = CustomerStatus.Active },
    new Customer { Id = 2, Name = "李四", Status = CustomerStatus.Inactive }
};

// 默认:属性列名使用 XafDisplayName / DisplayName / Display / 属性名
var table = ListTableBridge.ListTableBridge.ToDataTable(customers);

生成 DataTable 的列名示例:

  • Id 列:"客户编号"(来自 XafDisplayName
  • Name 列:"客户名称"(来自 DisplayName
  • Status 列:"状态"(来自 Display

2. DataTable → List<T>(静态方法)

using System.Data;
using ListTableBridge;

DataTable table = /* 来自数据库或其他来源 */;

// 列名可以是属性名或特性定义的显示名
var customers = ListTableBridge.ListTableBridge.ToList<Customer>(table);

列名匹配规则:

  • 列名在以下集合内任意一个即可匹配到属性:
    • XafDisplayName
    • DisplayName
    • Display
    • 属性原始名称
  • 匹配大小写不敏感。

3. 扩展方法:ToDataTable / ToList / IDataReader.ToList

除了直接调用 ListTableBridge.ListTableBridge 上的静态方法之外,你也可以使用扩展方法,让调用更自然:

using System.Collections.Generic;
using System.Data;
using ListTableBridge;

var list = new List<Customer>
{
    new Customer { Id = 1, Name = "张三", Status = CustomerStatus.Active },
    new Customer { Id = 2, Name = "李四", Status = CustomerStatus.Inactive }
};

// 1) 集合 → DataTable
DataTable table = list.ToDataTable();

// 2) DataTable → List<T>
List<Customer> customers = table.ToList<Customer>();

// 3) IDataReader → List<T>(流式读取,不需要中间 DataTable)
using (var reader = table.CreateDataReader())
{
    List<Customer> customersFromReader = reader.ToList<Customer>();
}

// 4) 异步版本(基于 Task 封装)
DataTable tableAsync = await list.ToDataTableAsync();
List<Customer> customersAsync = await tableAsync.ToListAsync<Customer>();
using (var reader = table.CreateDataReader())
{
    List<Customer> customersFromReaderAsync = await reader.ToListAsync<Customer>();
}

所有扩展方法都支持可选参数:

  • TypeMappingConfig config:自定义类型转换规则
  • bool enableElementFeatureReading:控制是否从枚举元素特性中读取显示名

4. 部分列映射示例(includeColumns / columnFilter)

在某些场景下,你只希望映射实体中的部分属性,可以使用以下两种方式:

using System.Collections.Generic;
using System.Data;
using ListTableBridge;

var list = new List<Customer>
{
    new Customer { Id = 1, Name = "张三", Status = CustomerStatus.Active },
    new Customer { Id = 2, Name = "李四", Status = CustomerStatus.Inactive }
};

// 1) includeColumns:按列名(属性名或显示名)精确指定
DataTable onlyIdAndName = ListTableBridge.ListTableBridge.ToDataTable(
    list,
    new[] { "Id", "Name" } // 也可以使用显示名,如 "客户编号", "客户名称"
);

// 2) columnFilter:按属性元数据动态筛选
DataTable onlyId = ListTableBridge.ListTableBridge.ToDataTable(
    list,
    property => property.Name == nameof(Customer.Id)
);

// 3) DataTable → List<T> 时同样支持部分列映射
List<Customer> fromIncludeColumns = ListTableBridge.ListTableBridge.ToList<Customer>(
    onlyIdAndName,
    new[] { "Id", "Name" }
);

List<Customer> fromFilter = ListTableBridge.ListTableBridge.ToList<Customer>(
    onlyIdAndName,
    property => property.Name == nameof(Customer.Id)
);

说明:

  • includeColumns 支持属性名、XafDisplayNameDisplayNameDisplay 以及 ColumnMappingAttribute 指定的列名,大小写不敏感;
  • includeColumns 中包含在类型或 DataTable 中不存在的列名时,将抛出 ArgumentException,并在消息中标明缺失列名;
  • columnFilter 通过 PropertyInfo 进行筛选,便于结合自定义特性做按标签导出;
  • 原有不带 includeColumns / columnFilter 的重载保持行为不变,仍然映射所有可映射属性。

枚举元素特性读取(enableElementFeatureReading)

对于 枚举字段本身(即列类型为字符串时),可以控制是否使用枚举元素上的特性作为字符串值。

List<T> → DataTable

var table = ListTableBridge.ListTableBridge.ToDataTable(
    customers,
    enableElementFeatureReading: true
);

行为:

  • enableElementFeatureReading == true 时:

    • 如果枚举元素上存在 XafDisplayName / DisplayName / Display,写入其显示名
    • 否则写入枚举名称(Active, Inactive
  • enableElementFeatureReading == false(默认):

    • 始终写入枚举名称(Active, Inactive),不读取枚举元素特性

DataTable → List<T>

var customers = ListTableBridge.ListTableBridge.ToList<Customer>(
    table,
    enableElementFeatureReading: true
);

行为:

  • 枚举列为字符串时,解析顺序:

    1. 尝试按枚举 名称 解析(如 "Active"
    2. 失败时,按 XafDisplayName / DisplayName / Display 定义的显示名匹配
    3. 如果仍失败,最后再交给 Enum.Parse 抛出一致的异常
  • enableElementFeatureReading == false

    • 仅按名称或数值解析,不使用枚举元素特性。

类型映射与空值处理

内部通过 TypeMappingConfig 提供统一的类型转换:

  • DBNull.Valuenull(对于引用类型和可空值类型)
  • 非可空值类型在遇到 null/DBNull 时使用默认值(例如 0, false
  • 枚举:
    • 字符串 → Enum.Parse
    • 数值 → 转为枚举底层类型,再通过 Enum.ToObject
  • 特殊类型:
    • Guid:支持 Guid 或字符串
    • DateTimeOffset:支持 DateTimeOffset, DateTime, 字符串
    • TimeSpan:支持 TimeSpan, 字符串

你可以通过注册自定义转换器扩展 TypeMappingConfig

TypeMappingConfig.Default.Register(
    typeof(MyCustomType),
    v => MyCustomType.Parse(v.ToString())
);

性能说明

项目中包含性能测试用例(基于 xUnit):

  • 使用 10,000 条记录进行 List<T> → DataTable → List<T> 循环测试
  • 内部使用表达式树编译 Getter/Setter 并缓存 TypeMetadata
  • 典型场景下在普通开发机上可满足毫秒级转换需求(具体耗时取决于对象复杂度和运行环境)

测试

运行全部单元测试:

dotnet test .\ListTableBridge.sln

当前测试覆盖的主要内容:

  • 基础类型与可空类型双向转换
  • 各数值子类型(int, long, short, byte, float, double, decimal)与可空组合
  • DBNull 与可空类型映射
  • 枚举字符串与数值转换
  • XafDisplayNameDisplayName / Display 的优先级验证
  • 枚举元素特性读取开关 enableElementFeatureReading 的开启/关闭行为
  • 特殊字符串(Unicode、长文本等)场景

版本与兼容性建议

  • 初始版本建议:1.0.0
  • 后续版本遵循 Semantic Versioning
    • BREAKING CHANGE(破坏性变更,如签名变更)→ 主版本号 MAJOR +1
    • 新特性、兼容性扩展 → 次版本号 MINOR +1
    • Bug 修复、内部实现优化 → 修订号 PATCH +1

许可协议

This project is licensed under the MIT License.

You are free to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the software, subject to the standard MIT terms.

See the full license text in the LICENSE file (or MIT template) in your distribution.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net45 is compatible.  net451 was computed.  net452 was computed.  net46 was computed.  net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.2 125 3/1/2026
1.0.1 107 2/20/2026