C# 如何在转换为json期间转换对象?

C# 如何在转换为json期间转换对象?,c#,asp.net,.net,asp.net-web-api,C#,Asp.net,.net,Asp.net Web Api,我有一个扁平的DTO对象,有大约500个字段,通过API调用返回。NET机器将其转换为JSON,一切正常。看起来是这样的: { "id": 1, "desc": "foo", "system": "axmls", "bedrooms": 5, "flooring": "tile", "roof"

我有一个扁平的DTO对象,有大约500个字段,通过API调用返回。NET机器将其转换为JSON,一切正常。看起来是这样的:

{
  "id": 1,
  "desc": "foo",
  "system": "axmls",
  "bedrooms": 5,
  "flooring": "tile",
  "roof": "tesla",
  ...
  ...
}
现在,我被要求将这些~500个字段进行分类,使其看起来类似于以下内容:

{
  "main": {
    "id": 1,
    "desc": "foo",
    "system": "axmls",
    ...
  }
  "interior": {
    "bedrooms": 5,
    "flooring": "tile",
    ...
  }
  "exterior": {
    "roof": "tesla",
    ...
  }
}
我已经想到了几种方法来做这件事(没有太诱人)

  • 创建一个新对象以匹配此结构并将数据复制到其中。不太好
  • 手工构建JSON。没有
  • 使用Category属性标记原始对象上的每个字段,然后以某种方式在FilterAttribute中对其进行变换。这听起来很有希望,但我不知道如何实现它

  • 有没有一种方法可以以合理的方式创建这样的JSON结构?

    以下是我在评论中描述的内容。首先,您需要一些元数据。我在这里使用一个枚举(因为它减少了输入错误的可能性——尽管它确实使代码稍微复杂一些)

    更新:我发现了一个bug,我将所有内容都视为字符串。现在我将树的叶节点视为
    对象

    首先是类别类型:

    private enum CategoryName
    {
        Main,
        Interior,
        Exterior,
    }
    
    以及类别元数据:

    private static readonly Dictionary<string, CategoryName> _categoryMetadata =
        new Dictionary<string, CategoryName>
        {
            {"id", CategoryName.Main},
            {"desc", CategoryName.Main},
            {"system", CategoryName.Main},
            {"bedrooms", CategoryName.Interior},
            {"flooring", CategoryName.Interior},
            {"roof", CategoryName.Exterior}
        };
    
    最后是代码。正如我在评论“构建一个元数据字典(字符串,字符串),将每个项目(卧室、地板、屋顶)映射到类别(主要、内部、外部)。阅读您拥有的数据(大的初始列表)进入字典。然后遍历字典,在元数据中查找类别。最后用结果填充字典并将其序列化回JSON”:


    在现实生活中,您需要删除
    JsonConvert.Serialize
    调用中的
    Formatting.Indented
    参数。

    只是为了让它看起来多么简单:)

    不复制值的公开结构

    public class ExposedHouse
    {        
        public Main Main { get; }
        public Interior Interior { get; }
        public Exterior Exterior { get; }
    
        public ExposedHouse(House house)
        {
            Main = new Main(house);
            Interior = new Interior(house);
            Exterior = new Exterior (house);
        }
    
        public class Main
        {
            private readonly House _house;
    
            public int Id => _house.Id;
            public string Description => _house.Description;
            public string System => _house.System;
       
            public Main(House house) { _house = house; }
        }
    
        public class Interior
        {
            private readonly House _house;
    
            public int Bedrooms => _house.Bedrooms;
            public string Flooring => _house.Flooring;
    
            public Interior(House house) { _house = house; }
        }
    
        public class Exterior
        {
            private readonly House _house;
    
            public string Roof => _house.Flooring;
    
            public Exterior(House house) { _house = house; }
        }
    }
    
    var exposed = new ExposedHouse(house);
    return Ok(exposed);
    
    和转换,而不复制值

    public class ExposedHouse
    {        
        public Main Main { get; }
        public Interior Interior { get; }
        public Exterior Exterior { get; }
    
        public ExposedHouse(House house)
        {
            Main = new Main(house);
            Interior = new Interior(house);
            Exterior = new Exterior (house);
        }
    
        public class Main
        {
            private readonly House _house;
    
            public int Id => _house.Id;
            public string Description => _house.Description;
            public string System => _house.System;
       
            public Main(House house) { _house = house; }
        }
    
        public class Interior
        {
            private readonly House _house;
    
            public int Bedrooms => _house.Bedrooms;
            public string Flooring => _house.Flooring;
    
            public Interior(House house) { _house = house; }
        }
    
        public class Exterior
        {
            private readonly House _house;
    
            public string Roof => _house.Flooring;
    
            public Exterior(House house) { _house = house; }
        }
    }
    
    var exposed = new ExposedHouse(house);
    return Ok(exposed);
    

    如果将来需求发生变化,并且您需要以不同的格式设置某些值,那么使用这种方法,任何人都可以做到:)

    考虑。建立一个元数据字典(字符串,字符串),将每个项目(卧室、地板、屋顶)映射到类别(主要、内部、外部)。将您拥有的数据(大的初始列表)读入
    词典
    。然后浏览字典,在元数据中查找类别。最后用结果填充一个
    字典
    ,并将其序列化回JSONCreate一个新对象以匹配此结构并将数据复制到其中。不太好这是最简单的方法。可维护、可读,因为读者可以看到我们公开了不同的数据结构。可维护,因为您只有一个方法可以将原始数据结构转换为我们发送的数据结构。如果您想要@Fabio建议的非常简单的实现,请看下面我的答案。简单、可维护、自我记录我正在努力避免复制对象。请记住,它有500多个属性。我的意思是将500个项目复制并粘贴到正确的插槽中。我只是在相关属性上放置了一个Category属性,然后通过反射读取它们。@AngryHacker,当前的方法不是复制值,而是用不同的结构“表示”它们。这种方法不涉及反射“昂贵”,并为其他更改提供了良好的基础。例如,如果新的需求需要格式化一些特定的值——对于反射方法,您需要构建/查找/使用另一种通用方法,但对于这种方法,只需跳入代码并更改它;)@AngryHacker:您可能希望在
    if(_categoryMetadata.TryGetValue(item.Key,out var category))
    之后有一个
    else
    块来表示您缺少一个类别。我通常不会在示例代码中进行错误检查
    public class ExposedHouse
    {        
        public Main Main { get; }
        public Interior Interior { get; }
        public Exterior Exterior { get; }
    
        public ExposedHouse(House house)
        {
            Main = new Main(house);
            Interior = new Interior(house);
            Exterior = new Exterior (house);
        }
    
        public class Main
        {
            private readonly House _house;
    
            public int Id => _house.Id;
            public string Description => _house.Description;
            public string System => _house.System;
       
            public Main(House house) { _house = house; }
        }
    
        public class Interior
        {
            private readonly House _house;
    
            public int Bedrooms => _house.Bedrooms;
            public string Flooring => _house.Flooring;
    
            public Interior(House house) { _house = house; }
        }
    
        public class Exterior
        {
            private readonly House _house;
    
            public string Roof => _house.Flooring;
    
            public Exterior(House house) { _house = house; }
        }
    }
    
    var exposed = new ExposedHouse(house);
    return Ok(exposed);