这是我的要求:

作为一个Page个对象,它有一个字符串属性Name和一个包含Field个对象的通用列表. Field对象具有以下公共字符串字段Name和公共通用字段Value. Calue可以是类型string, int(..以及功能中的更多类型). 当它是一个整数值时,它应该有一个类型为int的最小值和最大值. 当它是字符串值时,它应该有一个int类型的MaxLength值.

我想用Json将这个Page对象序列化,并将其反序列化为Page对象.

这就是我try 过的:

public abstract class Field
{
    public string Name { get; set; }
    public abstract FieldType Type { get; }
}

public enum FieldType
{
    Text,
    Number,
}

public class StringField : Field
{
    public override FieldType Type => FieldType.Text;

    public string Value { get; set; }
    public int? MaxLength { get; set; }
}

public class NumberField : Field
{
    public override FieldType Type => FieldType.Number;

    public int Value { get; set; }
    public int? Min { get; set; }
    public int? Max { get; set; }
}


public class Page
{
    public string Name { get; set; }
    public IEnumerable<Field> Fields { get; set; }
}

[ApiController]
[Route("[controller]")]
public class DemoController : ControllerBase
{
    private readonly ILogger<DemoController> _logger;

    public DemoController(ILogger<DemoController> logger)
    {
        _logger = logger;
    }

    [HttpGet]
    public IActionResult Get()
    {
        var page = new Page
        {
            Name = "TestPage",
            Fields = new List<Field>
            {
                new StringField
                {
                    Name = "Textfield",
                    MaxLength = 10,
                    Value = "DefaultValue"
                },
                new NumberField
                {
                    Name = "NumberField",
                    Value = 5,
                    Min = 0,
                    Max = 10,
                }
            }
        };

        return Ok(page);
    }

    [HttpPost]
    public ActionResult Post([FromBody] Page value)
    {
        return Ok(value);
    }

但是Value没有被正确地序列化和反序列化. 我可以自由 Select 任何Nuget套餐和更换型号.

这是GET方法的输出:

{
    "name": "TestPage",
    "fields": [
        {
            "name": "Textfield",
            "type": 0
        },
        {
            "name": "NumberField",
            "type": 1
        }
    ]

}

推荐答案

正如@jonasH在注释中提到的,如果您使用的是System.Text.Json,则需要使用Polymorphic serialization来保存类型信息.

[JsonDerivedType(typeof(StringField), typeDiscriminator: "StringField")]
[JsonDerivedType(typeof(NumberField), typeDiscriminator: "NumberField")]
public abstract class Field
{
    public string Name { get; set; }
    public abstract FieldType Type { get; }
}

这里有一把小提琴说明了这一点:https://dotnetfiddle.net/fm7Cdv

一个额外的字段"$type"被添加到您的JSON中,用于存储对象的类型.这与您的Type属性略有冗余,因此您可以考虑将其删除.

{
  "name": "TestPage",
  "fields": [
    {
      "$type": "StringField",
      "type": 0,
      "value": "DefaultValue",
      "maxLength": 10,
      "name": "Textfield"
    },
    {
      "$type": "NumberField",
      "type": 1,
      "value": 5,
      "min": 0,
      "max": 10,
      "name": "NumberField"
    }
  ]
}

Csharp相关问答推荐

ASP.NET Core 8 Cors标题未显示

为什么.Equals(SS,StringComparison. ClientCultureIgnoreCase)在Net 4.8和6.0之间不同?

使用LINQ to XML获取元素值列表是不起作用的

具有单一导航属性的EF核心一对多关系

StackExchange.Redis.RedisServerException:调用ITransaction.ExecuteAsync()时出现错误未知命令取消监视

如何通过寻找向量长度来优化两个循环?

在不添加不必要的尾随零的情况下本地化浮点型?

C#Null判断处理失败

Lambda表达式如何与隐式强制转换一起工作?

EF核心新验证属性`DeniedValues`和`StringCompison`不起作用

如何将%{v_扩展}转换为%{v_扩展}>>

如何使用Npgsql从SELECT获得所有查询结果

序列化过程中的死循环

Visual Studio,Docker容器-容器调用:连接被拒绝

try 创建一个C#程序,该程序使用自动实现的属性、覆盖ToString()并使用子类

如何正确地在VB中初始化类?

使用DI实例化带有动态参数的服务?

使用免费的DotNet库从Azure函数向Azure文件共享上的现有Excel文件追加行

无法使用直接URL通过PictureBox.ImageLocation加载图像

根据运行时值获取泛型类型的字典