繁体   English   中英

反序列化实现 IEnumerable 的 class

[英]Deserialize a class that implements IEnumerable

我开发了一个小程序,它允许在 Json 中序列化/反序列化 class。

这个程序,我把它写成 .NET 7,因此我使用 System.Text.Json

所以我有一个 ITest 接口。 该接口在两个类 TestSuite 和 TestCase 中实现。

[JsonDerivedType(typeof(TestSuite), "testSuite")]
[JsonDerivedType(typeof(TestCase), "testCase")]
[JsonPolymorphic(UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToNearestAncestor)]
public interface ITest
{
}
public class TestCase : ITest
{
    public string Name { get; set; }
}
public class TestSuite : ITest, IEnumerable<ITest>
{
    private readonly List<ITest> _tests = new ();
 
    public void Add(ITest test)
    {
        _tests.Add(test);
    }
 
    /// <inheritdoc />
    public IEnumerator<ITest> GetEnumerator()
    {
        return _tests.GetEnumerator();
    }
 
    /// <inheritdoc />
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

为了测试,我这样做:

ITest suite = new TestSuite { new TestCase { Name = "Oui" }, new TestCase { Name = "Test2" } };
 
string json = JsonSerializer.Serialize(suite);
 
var s = JsonSerializer.Deserialize<ITest>(json);
 
Console.WriteLine(json);

TestCase 序列化和反序列化工作完美。

但是对于 TestSuite 反序列化失败并显示错误消息:

System.NotSupportedException: '集合类型 'Test.TestSuite' 是抽象的,一个接口,或者是只读的,无法实例化和填充。 路径:$.$值 | 行号:0 | BytePositionInLine:32。

我不能使用自定义 JsonConverter,因为 json 多态性默认仅支持 json 转换器。

你知道我怎么解决这个问题吗?

提前致谢,

我试图为 TestSuite 创建一个自定义的 JsonConverter,但我做不到。 然后我尝试中止 json 多态性并为 ITest 创建自定义 JsonConverter 但这不是一个好主意。

这里的问题是你的 class 实现了一个集合接口,ATM 没有内置的方式告诉System.Text.Json将你的 object 序列化为 object,而不是作为一个集合(跟踪这个集合何时可能)。

如果你真的真的需要使用当前的 class 结构,你可以 go 进入反射的兔子洞并弄乱System.Text.Json内部结构(注意这可能非常脆弱):

// tells to serialize `TestSuite` as object
internal sealed class ObjectConverterFactory : JsonConverterFactory
{
    public override bool CanConvert(Type typeToConvert)
    {
        return typeToConvert == typeof(TestSuite);
    }

    public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
    {
        var type = typeof(JsonConverterFactory).Assembly.GetType("System.Text.Json.Serialization.Converters.ObjectConverterFactory");
        var f = (JsonConverterFactory)Activator.CreateInstance(type, new object[]{true});
        return  f.CreateConverter(typeToConvert, options);
    }
}

// exposes private property to serializer
static void Test(JsonTypeInfo jsonTypeInfo)
{
    if (jsonTypeInfo.Type == typeof(TestSuite))
    {
        var field = typeof(TestSuite).GetField("_tests", BindingFlags.Instance | BindingFlags.NonPublic);
        JsonPropertyInfo jsonPropertyInfo = jsonTypeInfo.CreateJsonPropertyInfo(field.FieldType, field.Name);
        jsonPropertyInfo.Get = field.GetValue;
        jsonPropertyInfo.Set = field.SetValue;
        jsonTypeInfo.Properties.Add(jsonPropertyInfo);
    }
}

和用法:

ITest suite = new TestSuite { new TestCase { Name = "Oui" }, new TestCase { Name = "Test2" } };

var jsonSerializerOptions = new JsonSerializerOptions
{
    Converters = { new ObjectConverterFactory() },
    TypeInfoResolver = new DefaultJsonTypeInfoResolver
    {
        Modifiers = { Test }
    }
};
string json1 = JsonSerializer.Serialize(suite, jsonSerializerOptions);

var s = JsonSerializer.Deserialize<ITest>(json1, jsonSerializerOptions);

再次注意,这可能非常脆弱(主要是由于ObjectConverterFactory的实现),我建议从TestSuite中删除IEnumerable<ITest>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM