C#多类型用户输入层级存储的类型安全数据结构选型咨询
请提供需要使用Markdown格式化的具体内容,以下是按你指定规则的格式示例:
一级标题
二级标题
- 无序列表项1
- 无序列表项2
这是强调的文本
Console.WriteLine("Hello World");
这是一段引用的文本
若你需要格式化的是之前的C#层级化输入存储问题,以下是格式化后的完整内容及解决方案:
C#层级化用户输入存储方案咨询
我正在开发一款C#应用,需存储大量不同类型(字符串、双精度浮点数、布尔值)的用户输入,且输入需按层级(类别、子类别等)组织,所有输入值均被封装在InputProperty<T>类中,该类存储实际值及附加数据。
层级结构示例:
Input data -catA --catAA ---propAAA ---propAAB --catAB ---catABA ----propABAA ---propABA -catB --propBA -catC --catCA ---catCAA ----propCAAA
每个类别可包含子类别、输入属性或两者兼具。核心需求如下:
- 支持类型安全地访问任意类别或属性,例如
inputData.catA.catAA.propAAA,IDE可提前提示不存在的类别/属性; - 可获取某类别及其所有子类别中的全部属性,例如调用
catA.GetAllProperties()返回包含propAAA、propAAB、propABAA、propABA的列表; - 可轻松进行序列化/反序列化及深拷贝操作。
我已考虑两种方案:
- 为每个类别创建唯一类,继承提供
GetAllProperties功能的接口和基类,子类别与输入属性作为类字段。该方案满足需求1、2,但序列化/反序列化、深拷贝实现复杂,且需编写大量重复类,代码冗余; - 使用单一类别类,通过
subcategories和inputProperties字典构建层级。该方案满足需求2、3,但无法实现类型安全访问,需通过字符串索引导航,IDE无法提前报错,且C#无原生字符串枚举支持,需临时方案,并非最优解。
恳请推荐更优解决方案。
推荐解决方案:代码生成+基类组合模式
方案思路
结合代码生成自动创建类型安全的类别类,同时让每个类别类继承同一个提供通用功能的基类,兼顾类型安全、层级遍历、序列化三大需求。
具体实现步骤
定义通用基类
创建一个抽象基类CategoryBase,内置GetAllProperties()方法用于递归遍历所有子类别属性,同时实现序列化特性与深拷贝方法:public abstract class CategoryBase { private readonly List<CategoryBase> _subCategories = new(); private readonly List<object> _properties = new(); protected void RegisterSubCategory(CategoryBase subCategory) { _subCategories.Add(subCategory); } protected void RegisterProperty(object property) { _properties.Add(property); } public IEnumerable<InputProperty<object>> GetAllProperties() { var result = new List<InputProperty<object>>(); // 添加当前类别的属性 result.AddRange(_properties.Cast<InputProperty<object>>()); // 递归添加子类别属性 foreach (var subCat in _subCategories) { result.AddRange(subCat.GetAllProperties()); } return result; } // 基于序列化实现深拷贝 public virtual T DeepCopy<T>() where T : CategoryBase { var json = System.Text.Json.JsonSerializer.Serialize(this); return System.Text.Json.JsonSerializer.Deserialize<T>(json); } }编写代码生成模板
使用T4模板或Roslyn代码生成工具,根据层级结构配置文件(如JSON/YAML)自动生成强类型类别类。例如针对catA和catAA生成的代码:public class CatA : CategoryBase { public CatAA CatAA { get; } public CatAB CatAB { get; } public CatA() { CatAA = new CatAA(); RegisterSubCategory(CatAA); CatAB = new CatAB(); RegisterSubCategory(CatAB); } } public class CatAA : CategoryBase { public InputProperty<string> PropAAA { get; } public InputProperty<double> PropAAB { get; } public CatAA() { PropAAA = new InputProperty<string>(); RegisterProperty(PropAAA); PropAAB = new InputProperty<double>(); RegisterProperty(PropAAB); } }使用方式
生成代码后即可实现类型安全访问、属性遍历与深拷贝:var inputData = new InputData(); // IDE智能提示属性与类别 inputData.CatA.CatAA.PropAAA.Value = "Test"; // 获取catA下所有属性 var allProps = inputData.CatA.GetAllProperties(); // 深拷贝catA var clonedCatA = inputData.CatA.DeepCopy<CatA>();
方案优势
- 类型安全:自动生成的强类型类支持IDE智能提示,编译时即可检测错误;
- 低冗余:修改层级结构只需更新配置文件,重新生成代码即可;
- 通用能力:基类内置遍历、序列化、深拷贝逻辑,无需重复编写;
- 高性能:代码生成的强类型访问比反射或字典索引效率更高。
轻量化替代方案:嵌套记录+反射工具
若不想用代码生成,可定义嵌套记录类型,搭配反射工具实现属性遍历:
public record InputData(CatA CatA, CatB CatB, CatC CatC); public record CatA(CatAA CatAA, CatAB CatAB); public record CatAA(InputProperty<string> PropAAA, InputProperty<double> PropAAB); // ...其他嵌套记录类 // 反射工具类实现遍历 public static class CategoryHelper { public static IEnumerable<InputProperty<object>> GetAllProperties(object category) { var props = new List<InputProperty<object>>(); foreach (var prop in category.GetType().GetProperties()) { var value = prop.GetValue(category); if (value is InputProperty<object> inputProp) { props.Add(inputProp); } else if (value != null && !prop.PropertyType.IsValueType && prop.PropertyType != typeof(string)) { props.AddRange(GetAllProperties(value)); } } return props; } }
该方案无需代码生成,但反射遍历性能略低,适合层级结构不频繁变更的场景。
内容的提问来源于stack exchange,提问作者Justin8051
相关产品推荐
相关产品推荐

