【问题标题】:Is there a way to define classes inline upon their usage?有没有办法在使用时内联定义类?
【发布时间】:2019-04-12 21:48:14
【问题描述】:

我正在编写一项服务,以通过 HTTP 从我公司的另一个团队的 API 中检索数据。来自他们 API 的 JSON 响应体看起来有点像这样:

"SomeObject": {
    "SomeInnerObject": {
        "SomeProperty": {
            "Id": "123",
            "Type": "abc",
            "Name": "some value"
        }
    }
}

我正在编写一个 C# 类来将数据存储在内存中,以便进行一些比较。 JSON 对象的嵌套导致类看起来令人讨厌的重复:

public class MyClass 
{
    public SomeObjectModel SomeObject { get; set; }
    public class SomeObjectModel
    {
        public SomeInnerObjectModel InnerObject { get; set; }
        public class SomeInnerObjectModel
        {
            // etc...
        }
    }
}

我确信内部类,如“SomeObjectModel”,只会被读取而不是在其他地方实例化,所以有没有办法将类定义和属性定义行组合成更像这样的东西?

public class MyClass
{
    public SomeObject { get; set; } :
    {
        public SomeInnerObject { get; set; } :
        {
            // etc...
        }
    }
}

编辑:

JSON 中将包含数组,因此如果您提出使用泛型等的替代方案,请考虑这一点。

【问题讨论】:

  • 请注意,类声明本身不需要嵌套即可以嵌套方式使用它们。您可以将SomeInnerObject 类声明在与SomeObject 相同的级别,但仍然在SomeObject 内使用SomeInnerObject

标签: c# json


【解决方案1】:

如果你只是用它来反序列化 JSON,你甚至不需要定义一个类。你可以使用嵌套的anonymous type

首先,创建并填充(使用虚拟值)具有您需要能够读取的属性的匿名类型。然后将其作为第二个参数传递给DeserializeAnonymousType<T>(string,T)

结果是您创建的同一匿名类型的新实例,但现在它填充了来自 JSON 的值。

var json = @"{'SomeObject': {'SomeInnerObject': {'SomeProperty': {'Id': '123','Type': 'abc','Name': 'some value'}}}}";

var template = new
{
    SomeObject = new
    {
        SomeInnerObject = new 
        { 
            SomeProperty = new 
            {
               Id = default(int),
               Type = default(string),
               Name = default(string)
            }
        }
    }
};

var result = JsonConvert.DeserializeAnonymousType(json, template);
var id = result.SomeObject.SomeInnerObject.SomeProperty.Id;
var type = result.SomeObject.SomeInnerObject.SomeProperty.Type;
var name = result.SomeObject.SomeInnerObject.SomeProperty.Name;

Console.WriteLine("{0} {1} {2}", id, type, name);

输出:

123 abc some value

见我的working example on DotNetFiddle

编辑:如果您的 JSON 包含一个数组,您可以使用 new[] {} 根据类型推断创建一个数组,然后将匿名类型放入其中,如下所示:

var json = @"{ 'SomeObjects': [ { 'Id': '123', 'Name': 'some value' }, { 'Id': '456', 'Name': 'another value' } ]}";

var template = new
{
    SomeObjects = new [] { new { Id=default(int), Name=default(string)} }
};

【讨论】:

  • 我更希望它是一个类定义,但我对此并不执着,我想这可能是我最好的选择。
  • 如何使用 JSON 创建这样的模板? "SomeObjects": [ { "Id": "123", "Name": "some value" }, { "Id": "456", "Name": "another value" }, ]
  • 我更新了我的答案和 DotNetFiddle 示例,以演示如何处理这种 JSON。
【解决方案2】:

简短的回答是否定的,C# 不支持该语法糖的任何版本。 C# 中最接近的可能是匿名类型或值元组。

其他语言也有类似的特点:

  • C++ 在声明中支持“内联类”。
  • Java 支持比 C# 匿名记录类型更复杂的匿名类。
  • Scala 支持在声明头中声明其成员的案例类。

等等。我认为第一个是最接近您正在寻找的东西。

在过去的十年中,C# 已经多次提出了 Scala 风格的类声明,并且最终可能会进入 C# 8;见https://blog.cdemi.io/whats-coming-in-c-8-0-records/

【讨论】:

    【解决方案3】:

    您可以使用dynamic type。这是一个最小的例子:

    using Newtonsoft.Json;
    using System;
    
    namespace ConsoleApp1
    {
        class Program
        {
            static void Main(string[] args)
            {
                dynamic x = JsonConvert.DeserializeObject("[{key: '1001', value: 'test'}, {key: '1002', value: 'test2'}, ]");
                Console.WriteLine(x[0].key);
                Console.WriteLine(x[0].value);
                Console.WriteLine(x[1].key);
                Console.WriteLine(x[1].value);
                Console.ReadLine();
            }
        }
    }
    

    【讨论】:

    • 我不是在寻找动态对象,我希望它被显式键入。
    • 根据定义,类是静态的(如“静态类型”),因此您不能即时构建类。 dynamic 的目的是解决您的需求。
    • 对,所以我本质上是在要求一个显式类型的非静态类,我感觉它不存在。
    • @Werns 正确。因为如果您考虑一下,该类型必须在编译时可用以进行类型检查。另一种方法是使用tuple
    【解决方案4】:

    【讨论】:

    • 将来知道很酷,但目前来自外部 API 的 JSON 比我需要的数据大 2-3 倍,所以需要更多时间来删除我不需要的数据'我需要的不仅仅是制造我真正需要的东西。
    猜你喜欢
    • 1970-01-01
    • 2018-12-09
    • 2023-01-26
    • 2011-08-12
    • 1970-01-01
    • 2017-08-24
    • 1970-01-01
    • 2023-04-09
    • 2011-07-04
    相关资源
    最近更新 更多