面向对象可变列数容器类设计方案咨询
可变列数数据容器的面向对象设计方案
你需要的是一个能容纳每行列数可变的数据容器,无需为每种列数组合预定义子类。下面是几种无需预定义所有列数组合的可行方案:
方案1:使用键值对字典存储每行数据
直接用Dictionary<string, object>存储每行的列名和对应值,容器类持有这类字典的列表。这种方式完全灵活,不需要预定义任何子类。
public class DynamicColumnContainer { public List<Dictionary<string, object>> Rows { get; } = new List<Dictionary<string, object>>(); // 辅助方法:添加一行数据 public void AddRow(Dictionary<string, object> row) { Rows.Add(row); } // 示例:添加指定列的行 public void AddRow(string column1, object value1, string column2, object value2) { var row = new Dictionary<string, object> { { column1, value1 }, { column2, value2 } }; Rows.Add(row); } }
优点:完全灵活,支持任意列数和列名;无需预定义类型。
缺点:丢失编译时类型安全,使用时需要强制转换值类型;没有IntelliSense提示。
方案2:使用强类型的列表存储每行数据
如果每行的数据类型统一(比如都是int),可以用List<T>存储每行的列值,容器类持有List<List<T>>。如果类型不统一,用List<object>。
public class TypedDynamicContainer<T> { public List<List<T>> Rows { get; } = new List<List<T>>(); public void AddRow(params T[] values) { Rows.Add(values.ToList()); } } // 使用示例 var container = new TypedDynamicContainer<int>(); container.AddRow(1, 2); // 2列的行 container.AddRow(3, 4, 5, 6); // 4列的行
优点:保持了类型安全;实现简单,无需额外类。
缺点:每行没有列名,只能通过索引访问;如果需要混合类型,只能用object,同样会丢失类型安全。
方案3:使用自定义动态行类
创建一个封装了列值存储的类,通过索引器或泛型方法访问,兼顾灵活性和一定的类型安全。
public class DynamicRow { private readonly List<object> _values = new List<object>(); public IReadOnlyList<object> Values => _values.AsReadOnly(); public int ColumnCount => _values.Count; public DynamicRow(params object[] values) { _values.AddRange(values); } // 索引器访问 public object this[int index] { get => _values[index]; set => _values[index] = value; } // 泛型方法获取值,避免强制转换 public T GetValue<T>(int index) { return (T)_values[index]; } } public class DynamicContainer { public List<DynamicRow> Rows { get; } = new List<DynamicRow>(); public void AddRow(DynamicRow row) { Rows.Add(row); } public void AddRow(params object[] values) { Rows.Add(new DynamicRow(values)); } }
优点:有统一的行类型,容器管理更清晰;通过泛型方法GetValue<T>减少强制转换的繁琐。
缺点:仍然没有列名,只能通过索引访问;类型安全依赖运行时检查。
方案4:结合ExpandoObject实现动态属性行
利用C#的ExpandoObject,可以像访问静态属性一样访问动态添加的列,同时保留灵活性。
public class ExpandoContainer { public List<dynamic> Rows { get; } = new List<dynamic>(); public void AddRow(dynamic row) { Rows.Add(row); } // 示例:创建带指定属性的行 public dynamic CreateRow(params (string Name, object Value)[] columns) { dynamic row = new ExpandoObject(); var rowDict = (IDictionary<string, object>)row; foreach (var (name, value) in columns) { rowDict[name] = value; } return row; } } // 使用示例 var container = new ExpandoContainer(); var row1 = container.CreateRow(("ValueA", 1), ("ValueB", 2)); var row2 = container.CreateRow(("ValueA", 3), ("ValueB", 4), ("ValueC", 5), ("ValueD", 6)); container.AddRow(row1); container.AddRow(row2); // 访问行数据 int val = row1.ValueA;
优点:支持动态属性访问,语法接近静态类;完全灵活,支持任意列数和列名。
缺点:丢失编译时类型安全,属性名拼写错误只会在运行时暴露;性能略低于静态类型。
方案选择建议
- 如果需要完全灵活且不介意类型安全:选方案1或方案4。
- 如果需要类型安全且不需要列名:选方案2。
- 如果需要统一行类型且希望简化值访问:选方案3。
内容的提问来源于stack exchange,提问作者sdub0800
相关产品推荐
相关产品推荐

