c# datatable 的用法

来源:这里教程网 时间:2026-02-21 17:35:57 作者:

DataTable 创建和列定义怎么写才不踩坑

直接 new

DataTable()
没问题,但列类型必须明确指定,否则后续赋值
DBNull.Value
或类型不匹配时会抛异常(比如把
"123"
int
列里塞)。别用
dt.Columns.Add("Name")
这种无类型写法——它默认是
string
,但掩盖了设计意图,后期改类型或导出到数据库时容易出错。

推荐写法:
dt.Columns.Add("Id", typeof(int))
new DataColumn("Name", typeof(string))
注意:
typeof(string)
System.Type.GetType("System.String")
更简洁、更安全(后者字符串拼错就 null)
如果列可能为空,
int?
不被 DataTable 原生支持,得用
typeof(int)
+ 允许
DBNull.Value
,读取时用
row["Id"] == DBNull.Value ? null : (int?)row["Id"]

添加行为什么用
ImportRow
而不是
Rows.Add(dr)

当你从另一个

DataTable
里取
DataRow
(比如
src.Select("...")[0]
),再往目标表加时,直接
dst.Rows.Add(dr)
会报错:“该行已经属于另一个表”。这是 DataTable 的所有权机制导致的——
DataRow
绑定在创建它的表上。

正确做法是:
dst.ImportRow(dr)
,它复制数据和状态(包括
RowState
),不破坏原行归属
Rows.Add(object[])
也安全,比如
dst.Rows.Add(srcRow.ItemArray)
,但丢失原始
RowState
和表达式列值
批量插入场景下,
ImportRow
Merge
快 100 倍(尤其多表合并时)

Select()
DefaultView.RowFilter
性能差在哪

查数据别一上来就用

dt.DefaultView.RowFilter = "Age > 25"; dt.DefaultView.ToTable()
。这会强制构建完整 DataView 并生成新表,内存和 CPU 开销大;而
dt.Select("Age > 25")
是纯内存扫描,返回
DataRow[]
,快且轻量。

小数据量(Select() 通常快 10–30 倍
Select()
不支持 LIKE 通配(只能用
column LIKE 'A%'
,且区分大小写),也不支持函数如
UPPER()
;需要这些就得切到
DefaultView
若要复用筛选逻辑,建议封装为方法并缓存
DataView
实例,而非反复
ToTable()

DataTable 大了以后卡顿,怎么救

界面绑定后还一边循环

Rows.Add()
一边刷新控件?那是典型“边绑边填”反模式。GridControl 等控件监听
Rows.CollectionChanged
,每加一行都触发重绘,1000 行可能卡死几十秒。

务必先解绑:
grid.DataSource = null
,填完再赋值
大数据量(>1w 行)优先考虑分页或虚拟滚动,而不是全量加载到 DataTable 避免在循环里反复调用
row["ColName"]
——改用
row[index]
(列序号)或提前缓存
DataColumn
对象
真要高性能遍历,用
dt.CreateDataReader()
,它比
foreach (DataRow r in dt.Rows)
少一半对象分配开销

最常被忽略的一点:DataTable 本质是内存中的关系表,不是 ORM 替代品。它适合中等规模、结构稳定、需离线操作的场景;一旦涉及复杂关联、实时计算或百万级数据,该换

System.Linq.Expressions
+
List<t></t>
或实体类集合了。

相关推荐