json - 使用 System.Text.Json 序列化实现接口的对象
问题描述
我有一个包含通用集合的大师班。集合中的元素具有不同的类型,并且每个都实现一个接口。
硕士课:
public class MasterClass
{
public ICollection<IElement> ElementCollection { get; set; }
}
元素合同:
public interface IElement
{
string Key { get; set; }
}
元素的两个样本:
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; }
}
我需要MasterClass
使用 Json 中的新System.Text.Json
库来序列化对象的实例。使用以下代码,
public string Serialize(MasterClass masterClass)
{
var options = new JsonSerializerOptions
{
WriteIndented = true,
};
return JsonSerializer.Serialize(masterClass, options);
}
我得到以下 JSON:
{
"ElementCollection":
[
{
"Key": "myElementAKey1"
},
{
"Key": "myElementAKey2"
},
{
"Key": "myElementBKey1"
}
]
}
代替:
{
"ElementCollection":
[
{
"Key": "myElementAKey1",
"AValue": "MyValueA-1"
},
{
"Key": "myElementAKey2",
"AValue": "MyValueA-2"
},
{
"Key": "myElementBKey1",
"AValue": "MyValueB-1"
}
]
}
我应该实现哪个类(转换器、编写器、...)以获得完整的 JSON?
在此先感谢您的帮助。
解决方案
这对我有用:
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);
}
用法:
var options =
new JsonSerializerOptions
{
Converters =
{
new TypeMappingConverter<BaseType, ImplementationType>()
}
};
JsonSerializer.Deserialize<Wrapper>(value, options);
测试:
[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; }
}
推荐阅读
- mysql - 我们如何使用 Exclusive 或在以下情况下?
- c++ - 使用 Diehard:如何为 Diehard Test 格式化合适的输入?
- json - 将原始字符串响应从 API 转换为 JSON 格式
- sql - 如何将多个序列号范围插入 SQL 中的 1 列?
- spring - 在 docker 中使用 gradle 设置活动弹簧配置文件没有任何效果
- android - 为什么我在我的 Android 应用程序中使用的可绘制对象在用作按钮背景时具有错误的纵横比
- java - 具有休眠依赖项的 Jar 文件无法使用 jdk 9+(openjdk 12)执行
- python - 为存储在对象列中的日期时间选择 DataFrame 行
- c# - .net core 2.1 ocelot 网关返回 404
- c# - 使用 Array.BinarySearch 在文本框上返回字符串