Newtonsoft.Json中的序列化/反序列化类层次结构

时间:2019-02-19 13:02:34

标签: c# json serialization json.net deserialization

我需要序列化/反序列化从一个或几个基本接口/抽象类派生的不同对象的列表。

这是我的模特:

public abstract class PaymentLogBase : IPaymentLog
{
    public StatisticsPaymentType Type { get; }

    public PaymentLogBase(StatisticsPaymentType type)
    {
        Type = type;
    }
}

public abstract class NumberedLog : PaymentLogBase
{
    public NumberedLog(StatisticsPaymentType type)
        : base(type)
    {

    }

    public string Number { get; set; }
}

public abstract class CardLog : NumberedLog
{
    public CardLog(StatisticsPaymentType type)
        : base(type)
    {

    }

    public string CardInfo { get; set; }
}

public abstract class CreditCardLog : CardLog
{
    public CreditCardLog(StatisticsPaymentType type)
        : base(type)
    {

    }

    public string Stan { get; set; }
}

public class CreditCardContactLessLog : CreditCardLog
{
    public CreditCardContactLessLog()
        : base(StatisticsPaymentType.ContactLessCc)
    {

    }
}

public class CreditCardContactLog : CreditCardLog
{
    public CreditCardContactLog()
        : base(StatisticsPaymentType.ContactCc)
    {

    }
}

public class UnsupportedCardLog : CardLog
{
    public UnsupportedCardLog()
        : base(StatisticsPaymentType.UnsupportedCard)
    {

    }
}

public class FuelCardLog : CardLog
{
    public FuelCardLog()
        : base(StatisticsPaymentType.FuelCard)
    {

    }
}

public class CashLog : PaymentLogBase
{
    public CashLog()
        : base(StatisticsPaymentType.Cash)
    {

    }
}

public class ITicketLog : NumberedLog
{
    public ITicketLog()
        : base(StatisticsPaymentType.Iticket)
    {

    }
}

internal class PaymentLogConverter : JsonConverter
{
    public override bool CanConvert(Type t) => t.IsAssignableFrom(typeof(PaymentLogBase));

    public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null || !CanConvert(t)) return null;
        try
        {
            JObject jo = JObject.Load(reader);
            // following is to avoid use of magic strings
            var typePropertyName = ((MemberExpression)((Expression<Func<PaymentLogBase, StatisticsPaymentType>>)(s => s.Type)).Body).Member.Name;

            object target = null;
            JToken jt = jo.GetValue(typePropertyName, StringComparison.InvariantCultureIgnoreCase);
            var propValue = jt.ToObject<StatisticsPaymentType>();
            switch (propValue)
            {
                case StatisticsPaymentType.FuelCard:
                    target = new FuelCardLog();
                    break;
                case StatisticsPaymentType.ContactCc:
                    target = new CreditCardContactLog();
                    break;
                case StatisticsPaymentType.ContactLessCc:
                    target = new CreditCardContactLessLog();
                    break;
                case StatisticsPaymentType.Iticket:
                    target = new ITicketLog();
                    break;
                case StatisticsPaymentType.UnsupportedCard:
                    target = new UnsupportedCardLog();
                    break;
                case StatisticsPaymentType.Cash:
                    target = new CashLog();
                    break;
                default:
                    target = null;
                    break;
            }

            if (target != null)
            {
                serializer.Populate(jo.CreateReader(), target);
            }

            return target;
        }
        catch (Exception ex)
        {
            throw new Exception("Can`t unmarshal type StatisticsPaymentType");
        }
    }

    public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
    {
        if (untypedValue == null)
        {
            serializer.Serialize(writer, null);
            return;
        }
        try
        {
            serializer.Serialize(writer, untypedValue);
        }
        catch (Exception ex)
        {
            throw new Exception("Can`t marshal type StatisticsPaymentType");
        }
    }

    public static readonly PaymentLogConverter Singleton = new PaymentLogConverter();
}

,当我将转换器指定为这样的属性时:

[JsonConverter(typeof(PaymentLogConverter))]
public abstract class PaymentLogBase

并尝试序列化这样的模型列表:

var list = new List<PaymentLogBase>();
list.Add(new CashLog());
list.Add(new CreditCardContactLessLog());
list.Add(new ITicketLog());
var json = JsonConvert.SerializeObject(list);

我进入例外:

Self referencing loop detected with type 'CashLog'. Path '.'.

当我像这样明确指定转换器时:

public static JsonSerializerSettings SerializerSettings => new JsonSerializerSettings()
    {
        Converters = {
            PaymentLogConverter.Singleton
        }
    };

并使用以下设置:

var json = JsonConvert.SerializeObject(list, SerializerSettings);

它做得很好,但是在传输数据的情况下,我无法应用这种使用方法,在服务器端,我还应该明确指定转换器

我该如何解决?

0 个答案:

没有答案