使用不可变的嵌套对象反序列化Json.NET

时间:2018-06-26 10:00:32

标签: c# json.net

我有以下C#类:

public RuleCondition(string field,
                     Operator @operator,
                     RightValueExpression rightValueExpression)
    {
        _operator = @operator;
        _field = field;
        _rightValueExpression = rightValueExpression;
    }
    public RightValueExpression ValueExpression => _rightValueExpression;
    public string Field => _field;
    public Operator Operator => _operator;
}

public sealed class RightValueExpression
{
    private readonly bool _relativeToBaseline;
    private readonly double _value;
    private readonly RightOperator _operator;
    private readonly PercentOrAbsolute _isPercent;
    public RightValueExpression(bool relativeToBaseline,
                                RightOperator @operator,
                                double value,
                                PercentOrAbsolute isPercent)
    {
        _isPercent = isPercent;
        _operator = @operator;
        _value = value;
        _relativeToBaseline = relativeToBaseline;
    }
    public PercentOrAbsolute IsPercent => _isPercent;
    public RightOperator Operator => _operator;
    public double Value => _value;
    public bool RelativeToBaseline => _relativeToBaseline;
}

public enum Operator
{
    GreaterThan,
    EqualTo,
    LessThan,
    GreaterThanEqualTo,
    LessThanEqualTo
}

public enum RightOperator
{
    Plus,
    Minus,
    Times,
    DividedBy
}
public enum PercentOrAbsolute
{
    Percent,
    Absolute
}

当使用Json.Net序列化到Json时,我得到以下信息:

var ruleCondition = new RuleCondition("Min", Operator.GreaterThan, new RightValueExpression(relativeToBaseline: true, RightOperator.Plus, 50, PercentOrAbsolute.Percent));
var json = JsonConvert.SerializeObject(ruleCondition);

Json:

{
"ValueExpression": {
    "IsPercent": 0,
    "Operator": 0,
    "Value": 50.0,
    "RelativeToBaseline": true
},
"Field": "Min",
"Operator": 0

}

很好,但是使用Json.Net反序列化

var des = JsonConvert.DeserializeObject<RuleCondition>(json);

RightValueExpression在RuleCondition中始终为空。

我需要自定义解串器吗?

2 个答案:

答案 0 :(得分:2)

您可以实现自定义JsonConverter:

class RuleConditionConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(RuleCondition));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);

        var @operator = (Operator)jo["Operator"].Value<int>();
        var field = jo["Field"].Value<string>();

        var isPercent = (PercentOrAbsolute)jo["ValueExpression"]["IsPercent"].Value<int>();
        var rigthOperator = (RightOperator)jo["ValueExpression"]["Operator"].Value<int>();
        var value = jo["ValueExpression"]["Value"].Value<double>();
        var relativeToBaseline = jo["ValueExpression"]["RelativeToBaseline"].Value<bool>();


        RuleCondition result = new RuleCondition(field, @operator, new RightValueExpression(relativeToBaseline, rigthOperator, value, isPercent));

        return result;
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

然后您可以在反序列化期间使用它:

var des = JsonConvert.DeserializeObject<RuleCondition>(json, new RuleConditionConverter());

答案 1 :(得分:1)

如果您可以使用ValueExpression属性的公共设置器,则可以避免使用专门的转换器:

  public class RuleCondition
  {
    public RuleCondition(string field,
                     Operator @operator,
                     RightValueExpression rightValueExpression)
    {
      ValueExpression = rightValueExpression;
      Field = field;
      Operator = @operator;
    }

    public RightValueExpression ValueExpression { get; set; }
    public string Field { get; }
    public Operator Operator { get; }
  }

或者,您可以将ValueExpression属性重命名为RightValueExpression

  public class RuleCondition
  {
    public RuleCondition(string field,
                     Operator @operator,
                     RightValueExpression rightValueExpression)
    {
      RightValueExpression = rightValueExpression;
      Field = field;
      Operator = @operator;
    }

    public RightValueExpression RightValueExpression { get; }
    public string Field { get; }
    public Operator Operator { get; }
  }