C#中动态修改DataTable列数据类型的优化方案咨询
问题描述
我需要在C#中创建一个DataTable,该表会被三个不同的场景调用,唯一差异是attr_value列的数据类型需分别设置为DateTime、Decimal或string。希望避免编写三个重复的DataTable创建方法,不确定用if-else是否合适,求合理解决思路。
现有代码实现
public class AttributeValueInsertDate : EntityBase { public static object ResolveRequest(AttributeValueList attributeValueList) { return new { dateValuesTVP = AttributeValue.CreateAttributeValueDataTable(attributeValueList) }; } } public class AttributeValueInsertDecimal : EntityBase { public static object ResolveRequest(AttributeValueList attributeValueList) { return new { decimalValuesTVP = AttributeValue.CreateAttributeValueDataTable(attributeValueList) }; } } public class AttributeValueInsertText : EntityBase { public static object ResolveRequest(AttributeValueList attributeValueList) { return new { textValuesTVP = AttributeValue.CreateAttributeValueDataTable(attributeValueList) }; } } public class AttributeValue { public static DataTable CreateAttributeValueDataTable(AttributeValueList attributeValueList) { var dataTable = new DataTable(); dataTable.Columns.Add("attr_id", typeof(Int32)); dataTable.Columns.Add("attr_value", typeof(DateTime)); dataTable.Columns.Add("effective_date", typeof(DateTime)); dataTable.Columns.Add("expiration_date", typeof(DateTime)); dataTable.Columns.Add("last_updated_user", typeof(string)); dataTable.Columns.Add("last_updated_date_time", typeof(DateTime)); if (attributeValueList.Count > 0) { foreach (var item in attributeValueList) { DataRow dr = dataTable.NewRow(); dr[0] = item.AttributeId; dr[1] = item.Value; dr[2] = item.EffectiveDate; dr[3] = item.ExpirationDate; dr[4] = item.LastUpdatedUser; dr[5] = item.LastUpdatedDate; dataTable.Rows.Add(dr); } } return dataTable; } }
解决方案
推荐两种简洁且易扩展的实现方式,比if-else更符合开闭原则:
方式一:传入Type参数指定列类型
修改CreateAttributeValueDataTable方法,增加一个Type参数来指定attr_value的类型,同时处理值的类型转换:
public class AttributeValue { public static DataTable CreateAttributeValueDataTable(AttributeValueList attributeValueList, Type attrValueType) { var dataTable = new DataTable(); dataTable.Columns.Add("attr_id", typeof(Int32)); dataTable.Columns.Add("attr_value", attrValueType); dataTable.Columns.Add("effective_date", typeof(DateTime)); dataTable.Columns.Add("expiration_date", typeof(DateTime)); dataTable.Columns.Add("last_updated_user", typeof(string)); dataTable.Columns.Add("last_updated_date_time", typeof(DateTime)); if (attributeValueList.Count > 0) { foreach (var item in attributeValueList) { DataRow dr = dataTable.NewRow(); dr[0] = item.AttributeId; // 转换值到目标类型,可根据实际情况添加异常处理 dr[1] = Convert.ChangeType(item.Value, attrValueType); dr[2] = item.EffectiveDate; dr[3] = item.ExpirationDate; dr[4] = item.LastUpdatedUser; dr[5] = item.LastUpdatedDate; dataTable.Rows.Add(dr); } } return dataTable; } }
然后修改三个调用类的ResolveRequest方法,传入对应类型:
public class AttributeValueInsertDate : EntityBase { public static object ResolveRequest(AttributeValueList attributeValueList) { return new { dateValuesTVP = AttributeValue.CreateAttributeValueDataTable(attributeValueList, typeof(DateTime)) }; } } public class AttributeValueInsertDecimal : EntityBase { public static object ResolveRequest(AttributeValueList attributeValueList) { return new { decimalValuesTVP = AttributeValue.CreateAttributeValueDataTable(attributeValueList, typeof(Decimal)) }; } } public class AttributeValueInsertText : EntityBase { public static object ResolveRequest(AttributeValueList attributeValueList) { return new { textValuesTVP = AttributeValue.CreateAttributeValueDataTable(attributeValueList, typeof(string)) }; } }
方式二:使用泛型方法
通过泛型参数约束attr_value的类型,代码更简洁且具备编译时类型检查:
public class AttributeValue { public static DataTable CreateAttributeValueDataTable<T>(AttributeValueList attributeValueList) { var dataTable = new DataTable(); dataTable.Columns.Add("attr_id", typeof(Int32)); dataTable.Columns.Add("attr_value", typeof(T)); dataTable.Columns.Add("effective_date", typeof(DateTime)); dataTable.Columns.Add("expiration_date", typeof(DateTime)); dataTable.Columns.Add("last_updated_user", typeof(string)); dataTable.Columns.Add("last_updated_date_time", typeof(DateTime)); if (attributeValueList.Count > 0) { foreach (var item in attributeValueList) { DataRow dr = dataTable.NewRow(); dr[0] = item.AttributeId; dr[1] = (T)Convert.ChangeType(item.Value, typeof(T)); dr[2] = item.EffectiveDate; dr[3] = item.ExpirationDate; dr[4] = item.LastUpdatedUser; dr[5] = item.LastUpdatedDate; dataTable.Rows.Add(dr); } } return dataTable; } }
调用时指定泛型类型:
public class AttributeValueInsertDate : EntityBase { public static object ResolveRequest(AttributeValueList attributeValueList) { return new { dateValuesTVP = AttributeValue.CreateAttributeValueDataTable<DateTime>(attributeValueList) }; } } public class AttributeValueInsertDecimal : EntityBase { public static object ResolveRequest(AttributeValueList attributeValueList) { return new { decimalValuesTVP = AttributeValue.CreateAttributeValueDataTable<Decimal>(attributeValueList) }; } } public class AttributeValueInsertText : EntityBase { public static object ResolveRequest(AttributeValueList attributeValueList) { return new { textValuesTVP = AttributeValue.CreateAttributeValueDataTable<string>(attributeValueList) }; } }
补充说明
- 两种方式都避免了重复代码,后续新增类型只需添加对应调用逻辑,无需修改DataTable创建方法本身;
- 若
item.Value的原始类型和目标类型转换存在风险,可在方法内添加try-catch或类型校验逻辑,避免运行时异常; - 不推荐用if-else:后续新增类型需修改方法内部判断逻辑,违反开闭原则,代码扩展性差。
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

