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 ?
在此先感谢您的帮助。
您正在寻找的称为多态序列化。
根据文档,您只需将接口转换为对象即可。例如:
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)
这对我有用:
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)
解决方案是实现一个通用转换器 ( 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 次 |
| 最近记录: |