




DataTable列定义须显式指定类型如dt.Columns.Add("Id", typeof(int)),避免默认string导致类型异常;跨表添加行用ImportRow而非Rows.Add;查数据优先Select()而非DefaultView.RowFilter。
直接 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() 不支持 LIKE 通配(只能用 column LIKE 'A%',且区分大小写),也不支持函数如 UPPER();需要这些就得切到 DefaultView
DataView 实例,而非反复 ToTable()
界面绑定后还一边循环 Rows.Add() 一边刷新控件?那是典型“边绑边填”反模式。GridControl 等控件监听 Rows.CollectionChanged,每加一行都触发重绘,1000 行可能卡死几十秒。
grid.DataSource = null,填完再赋值row["ColName"]——改用 row[index](列序号)或提前缓存 DataColumn 对象dt.CreateDataReader(),它比 foreach (DataRow r in dt.Rows) 少一半对象分配开销最常被忽略的一点:DataTable 本质是内存中的关系表,不是 ORM 替代品。它适合中等规模、结构稳定、需离线操作的场景;一旦涉及复杂关联、实时计算或百万级数据,该换 System.Linq.Expressions + List 或实体类集合了。