使用 System.Text.Json 序列化实现接口的对象

Rom*_* Eh 3 json .net-core-3.0 system.text.json

我有一个包含通用集合的大师班。集合中的元素有不同的类型,每个元素都实现了一个接口。

硕士课:

public class MasterClass
{
    public ICollection<IElement> ElementCollection { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

元素的契约:

public interface IElement
{
    string Key { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

元素的两个样本:

public class ElementA : IElement
{
    public string Key { get; set; }

    public string AValue { get; set; }
}

public class ElementB : IElement
{
    public string Key { get; set; }

    public string BValue { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我需要MasterClass使用System.Text.JsonJson 中的新库序列化对象实例。使用以下代码,

public string Serialize(MasterClass masterClass)
{
    var options = new JsonSerializerOptions
    {
        WriteIndented = true,
    };
    return JsonSerializer.Serialize(masterClass, options);
}
Run Code Online (Sandbox Code Playgroud)

我得到以下 JSON:

{
    "ElementCollection":
    [
        {
            "Key": "myElementAKey1"
        },
        {
            "Key": "myElementAKey2"
        },
        {
            "Key": "myElementBKey1"
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

代替:

{
    "ElementCollection":
    [
        {
            "Key": "myElementAKey1",
            "AValue": "MyValueA-1"
        },
        {
            "Key": "myElementAKey2",
            "AValue": "MyValueA-2"
        },
        {
            "Key": "myElementBKey1",
            "AValue": "MyValueB-1"
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

我应该实现哪个类(转换器、编写器、...)来获取完整的 JSON ?

在此先感谢您的帮助。

Lia*_*han 9

您正在寻找的称为多态序列化

这是微软文档文章

这是关于它的另一个问题

根据文档,您只需将接口转换为对象即可。例如:

public class TreeRow
{
    [JsonIgnore]
    public ICell[] Groups { get; set; } = new ICell[0];

    [JsonIgnore]
    public ICell[] Aggregates { get; set; } = new ICell[0];

    [JsonPropertyName("Groups")]
    public object[] JsonGroups => Groups;

    [JsonPropertyName("Aggregates")]
    public object[] JsonAggregates => Aggregates;


    public TreeRow[] Children { get; set; } = new TreeRow[0];
}
Run Code Online (Sandbox Code Playgroud)


Shi*_*mmy 5

这对我有用:

public class TypeMappingConverter<TType, TImplementation> : JsonConverter<TType>
  where TImplementation : TType
{
  [return: MaybeNull]
  public override TType Read(
    ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
      JsonSerializer.Deserialize<TImplementation>(ref reader, options);

  public override void Write(
    Utf8JsonWriter writer, TType value, JsonSerializerOptions options) =>
      JsonSerializer.Serialize(writer, (TImplementation)value!, options);
}
Run Code Online (Sandbox Code Playgroud)

用法:

var options =
   new JsonSerializerOptions 
   {
     Converters = 
     {
       new TypeMappingConverter<BaseType, ImplementationType>() 
     }
   };

JsonSerializer.Deserialize<Wrapper>(value, options);
Run Code Online (Sandbox Code Playgroud)

测试:

[Fact]
public void Should_serialize_references()
{
  // arrange
  var inputEntity = new Entity
  {
    References =
    {
      new Reference
      {
        MyProperty = "abcd"
      },
      new Reference
      {
        MyProperty = "abcd"
      }
    }
  };

  var options = new JsonSerializerOptions
  {
    WriteIndented = true,
    Converters =
    {
      new TypeMappingConverter<IReference, Reference>()
    }
  };

      var expectedOutput =
@"{
  ""References"": [
    {
      ""MyProperty"": ""abcd""
    },
    {
      ""MyProperty"": ""abcd""
    }
  ]
}";

  // act
  var actualOutput = JsonSerializer.Serialize(inputEntity, options);

  // assert
  Assert.Equal(expectedOutput, actualOutput);
}

[Fact]
public void Should_deserialize_references()
{
  // arrange

  var inputJson =
@"{
  ""References"": [
    {
      ""MyProperty"": ""abcd""
    },
    {
      ""MyProperty"": ""abcd""
    }
  ]
}";

  var expectedOutput = new Entity
  {
    References =
    {
      new Reference
      {
        MyProperty = "abcd"
      },
      new Reference
      {
        MyProperty = "abcd"
      }
    }
  };

  var options = new JsonSerializerOptions
  {
    WriteIndented = true
  };

  options.Converters.AddTypeMapping<IReference, Reference>();

  // act
  var actualOutput = JsonSerializer.Deserialize<Entity>(inputJson, options);

  // assert
  actualOutput
      .Should()
      .BeEquivalentTo(expectedOutput);
}


public class Entity
{
  HashSet<IReference>? _References;
  public ICollection<IReference> References
  {
    get => _References ??= new HashSet<IReference>();
    set => _References = value?.ToHashSet();
  }
}

public interface IReference
{
  public string? MyProperty { get; set; }
}

public class Reference : IReference
{
  public string? MyProperty { get; set; }
}
Run Code Online (Sandbox Code Playgroud)


Rom*_* Eh 3

解决方案是实现一个通用转换器 ( System.Text.Json.Serialization.JsonConverter) :

public class ElementConverter : JsonConverter<IElement>
{
    public override IElement Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, IElement value, JsonSerializerOptions options)
    {
        if (value is ElementA)
            JsonSerializer.Serialize(writer, value as ElementA, typeof(ElementA), options);
        else if (value is ElementB)
            JsonSerializer.Serialize(writer, value as ElementB, typeof(ElementB), options);
        else
            throw new ArgumentOutOfRangeException(nameof(value), $"Unknown implementation of the interface {nameof(IElement)} for the parameter {nameof(value)}. Unknown implementation: {value?.GetType().Name}");
    }
}
Run Code Online (Sandbox Code Playgroud)

只是该方法还需要做一些工作Read


归档时间:

查看次数:

2664 次

最近记录:

4 年,11 月 前