如何反序列化嵌套的多级多态类型

时间:2019-02-24 15:43:59

标签: asp.net polymorphism deserialization

你好,我有一个类的层次结构,在每个级别上都有一个char string[]={'c,'i','v','i','c'}; //size=5 // indexes: 0 1 2 3 4 字段和一个payload字段,通过它们可以反序列化有效负载。我的问题是如何对诸如此类的东西反序列化你我不想弄乱层次结构。

我需要在每个步骤中做出决定:

id

我已附上一张图片供进一步说明:
Hierarchy of classes

PS 我尝试使用 public class Root { public int id { get; set; } public Message msg { get; set; } } public abstract class Message { public int MessageID { get; set; } } public abstract class Com : Message { public int ComMsgId { get; set; } } public abstract class Game : Message { public int GameMsgID { get; set; } } public class Game1 : Game { public string Data { get; set; } } public class Com1 : Com { public bool IsDone { get; set; } } 库,但它不适用于多级多态性。我还能做些其他事情吗?

2 个答案:

答案 0 :(得分:1)

之所以没有更清洁的方法,是因为JSON不保存元数据信息,并且基于属性名称推断子类是一种非常复杂且占用大量资源的方法。

我通过在Message类中创建一个虚拟属性来解决此问题,该属性指示要反序列化的类的类型,并在每个子类中为其分配一个值。例如在Com1

public override string ClassName => nameof(Com1)

然后实现由CustomSubClassConverter继承的JsonConverter,您可以在其中重写ReadJson属性以通过对ClassName属性应用切换大小写来转换JSON。

然后用Message标记您的[JsonConverter(typeof(CustomSubClassConverter))]

如果您愿意,我将很高兴为您提供CustomSubClassConverter的代码。

更新

如果希望更容易适应新类的添加,还可以使用反射来获取子类,而不是使用switch / cases

答案 1 :(得分:0)

我已经通过将abstract字段用作属性中的discriminator来解决了该问题。此字段将在root中定义,并且仅在leaf中被覆盖- s。 然后我将单独实施有区别的工会。

为了能够在层次结构中的任何级别进行转换,我将用它们各自的叶子装饰中间抽象类:

例如,具有这样的类层次结构:

M
M1:MM2:M
[M11:M1M12:M1]; [M21:M2M22:M2]
叶子是M11,M12,M21,M22的地方,我写了以下代码:

[JsonConverter(typeof(JsonSubTypes.JsonSubtypes), propType)]
[JsonSubTypes.JsonSubtypes.KnownSubType(typeof(M.M1.M11),Leaf.M11)]
[JsonSubTypes.JsonSubtypes.KnownSubType(typeof(M.M1.M12), Leaf.M12)]
[JsonSubTypes.JsonSubtypes.KnownSubType(typeof(M.M2.M21), Leaf.M21)]
[JsonSubTypes.JsonSubtypes.KnownSubType(typeof(M.M2.M22), Leaf.M22)]
public abstract partial class M
{
    public static void Process(M message){

        switch(message.MKind){
            case M.Discriminator.M1 : M.M1.Process(message.AsM1);break;
            case M.Discriminator.M2: M.M2.Process(message.AsM2);break;
        }
    }
    [JsonIgnore]
    public bool IsM1=>this.MKind==Discriminator.M1;
    [JsonIgnore]
    public bool IsM2=>this.MKind==Discriminator.M2;
    [JsonIgnore]
    public M1 AsM1=>this as M1;
    [JsonIgnore]
    public M2 AsM2=>this as M2;
    private const string propType="$LeafKind";

    public enum Discriminator {
        M1=0,
        M2=1
    }
    public enum Leaf {
        M11=M1.Discriminator.M11*10,
        M12=M1.Discriminator.M12*10,
        M21=M2.Discriminator.M21*10,
        M22=M2.Discriminator.M22*10
    }



    [JsonProperty(propType)]
    public abstract Leaf LeafKind{get;}



    protected abstract Discriminator MKind{get;}
    public Discriminator Kind=>this.MKind;

    public DateTime timestamp { get;}
}

摘要分支(级别2)

       [JsonSubTypes.JsonSubtypes.KnownSubType(typeof(M.M1.M11), 
       M.Leaf.M11)]
       [JsonSubTypes.JsonSubtypes.KnownSubType(typeof(M.M1.M12),M.Leaf.M12)]
        public abstract partial class M1:M
        {
            public static   void  Process(M1 message){
                switch(message.M1Kind){
                    case M1.Discriminator.M11 : M1.M11.Process(message.AsM11);break;
                    case M1.Discriminator.M12:  M1.M12.Process(message.AsM12);break;
                }
            }
            protected override M.Discriminator MKind => M.Discriminator.M1;
            public new enum Discriminator {
                M11=10,
                M12=11
            }
            public new Discriminator Kind => this.M1Kind;

            protected abstract Discriminator M1Kind { get; }
            [JsonIgnore]
            public bool IsM11=>this.M1Kind==M1.Discriminator.M11;
            [JsonIgnore]
            public bool IsM12=>this.M1Kind==M1.Discriminator.M12;
            [JsonIgnore]
            public M11 AsM11=>this as M11;
            [JsonIgnore]
            public M12 AsM12=>this as M12;   
        }

叶子

public class M11 : M1
            {
                public static void Process(M11 message){
                    Console.WriteLine(message.Value);
                }

                public bool Value{get;set;}


                protected override Discriminator M1Kind => Discriminator.M11;

                public override Leaf LeafKind => Leaf.M11;
            }

要能够将类型为M11的对象强制转换为M1,我需要用M1装饰KnownSubTypes,但仅在{叶子。

PS 我还没有在此处添加所有discriminator,但是您可以在Source Code

中找到带有少量示例的完整实现

更新 我使用subtypes代替了字符串enum重新实现了层次结构。