【问题标题】:Json.net is not deserializing a list of objectJson.net 没有反序列化对象列表
【发布时间】:2014-04-22 15:16:35
【问题描述】:

我有以下模型结构:

public class Step : ActivityElement
{
    public Step()
    {
        this.Id = Guid.NewGuid();
        this.Label = "Basic Step";
        this.Type = "step";
    }

    public Guid Id { get; set; }
    public string Label { get; set; }
    public Input Input { get; set; }
}

public abstract class Input
{
    public string Type { get; set; }
    public object Value { get; set; }
}

public class GridInput : Input
{
    public GridInput()
    {
        this.Type = "grid";
        this.GridHeader = new GridHeader();
        this.RowList = new List<GridRow>();
    }

    public GridHeader GridHeader { get; set; }
    public List<GridRow> RowList { get; set; }
}

public class GridRow
{
    public GridRow()
    {
        this.IsDeleted = false;
        this.CellList = new List<GridCell>();
    }

    public List<GridCell> CellList { get; set; }
    public bool IsDeleted { get; set; }
}

public class GridCell
{
    public GridCell()
    {
        this.name = "not set yet";
        this.Input = null;
    }

    public string name { get; set; }
    public Input Input { get; set; }
}

这是我要反序列化的 JSON

{
    "Id":"e833ceae-57e5-4c52-8d56-b047790cb7c7",
    "Label":"Grid time!",
    "Input":
    {
        "GridHeader":{"ColumnDefinitionList":[{"field":"column1","title":"Column 1"},{"field":"column2","title":"Column 2"},{"field":"column3","title":"Column 3"},{"field":"column4","title":"Column 4"}]},
        "RowList":
        [
            {
                "CellList":
                [
                    {"name":"column1","Input":{"Type":"text","Value":"cell 1 row 1"}},
                    {"name":"column2","Input":{"Type":"text","Value":"cell 2 row 1"}},
                    {"name":"column3","Input":{"Type":"text","Value":"cell 3 row 1"}},
                    {"name":"column4","Input":{"Type":"text","Value":"cell 4 row 1"}}
                ],
                "IsDeleted":false
            },
            {
                "CellList":
                [
                    {"name":"column1","Input":{"Type":"text","Value":"cell 1 row 2"}},
                    {"name":"column2","Input":{"Type":"text","Value":"cell 2 row 2"}},
                    {"name":"column3","Input":{"Type":"text","Value":"cell 3 row 2"}},
                    {"name":"column4","Input":{"Type":"text","Value":"cell 4 row 2"}}
                ],
                "IsDeleted":false
            }
        ],
        "Type":"grid",
        "Value":null
    },
    "DisplayPosition":2,
    "Type":"step"
}

这是确保 GridInput 是作为输入创建的对象的自定义反序列化器:

public abstract class JsonCreationConverter<T> : JsonConverter
{
    protected abstract T Create(Type objectType, JObject jObject);

    public override bool CanConvert(Type objectType)
    {
        return typeof(T).IsAssignableFrom(objectType);
    }

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

        // Create target object based on JObject
        T target = Create(objectType, jObject);

        // Populate the object properties
        serializer.Populate(jObject.CreateReader(), target);

        return target;
    }
}
public class InputJsonConverter : JsonCreationConverter<Input>
{
    protected override Input Create(Type objectType, JObject jObject)
    {
        var type = (string)jObject.Property("Type");
        switch (type)
        {
            case "grid":
                return new GridInput();
            case "text":
                return new TextInput();
            case "dropdown":
                return new DropdownInput();
            case "checkbox":
                return new CheckboxInput();
        }

        throw new ApplicationException(String.Format("The given type {0} is not supported!", type));
    }
}

我已经实现了一些可以跳过 GridHeader(我不需要反序列化它,所以它只是在反序列化过程中创建一个空的 GridHeader),但 RowList 最终总是为空在 GridInput 反序列化之后。 我已经尝试了很多东西,但我的想法已经不多了......

TL:DR:GridInput 已创建,但 RowList 为空

【问题讨论】:

  • 尝试json2csharp.com,复制您的 JSON,这将为您生成匹配的架构。将其与您当前的架构进行比较,看看是否有问题。
  • this.RowList = new List&lt;GridRow&gt;(); 看起来你正在制作一个空的RowList
  • json实际上是从那些Model生成的,发送到视图,修改后发回。所有这些都使用 Json.Net
  • @Timothy,没有这个调用,Rowlist = null,所以问题仍然存在
  • @Zwik 你没有显示足够的代码。序列化和反序列化一些带有List&lt;T&gt; 成员的“普通的旧 C#”类在我这边工作得很好。

标签: c# json.net


【解决方案1】:

我无法重现该问题。您是否可能忘记让 Json.NET 使用 InputJsonConverter 类?以下代码有效。

void Main()
{
    var step = JsonConvert.DeserializeObject<Step>(s);
    Console.WriteLine(((GridInput)step.Input).RowList.Count); // 2
}
public class GridHeader { }
public class ActivityElement { public string Type { get; set; } }
public class Step : ActivityElement
{
    public Step()
    {
        this.Id = Guid.NewGuid();
        this.Label = "Basic Step";
        this.Type = "step";
    }

    public Guid Id { get; set; }
    public string Label { get; set; }
    public Input Input { get; set; }
}
[JsonConverter(typeof(InputJsonConverter))]
public abstract class Input
{
    public string Type { get; set; }
    public object Value { get; set; }
}

public class TextInput : Input
{
    public TextInput()
    {
        this.Type = "text";
    }
}
public class GridInput : Input
{
    public GridInput()
    {
        this.Type = "grid";
        this.GridHeader = new GridHeader();
        this.RowList = new List<GridRow>();
    }

    public GridHeader GridHeader { get; set; }
    public List<GridRow> RowList { get; set; }
}

public class GridRow
{
    public GridRow()
    {
        this.IsDeleted = false;
        this.CellList = new List<GridCell>();
    }

    public List<GridCell> CellList { get; set; }
    public bool IsDeleted { get; set; }
}

public class GridCell
{
    public GridCell()
    {
        this.name = "not set yet";
        this.Input = null;
    }

    public string name { get; set; }
    public Input Input { get; set; }
}
public abstract class JsonCreationConverter<T> : JsonConverter
{
    protected abstract T Create(Type objectType, JObject jObject);

    public override bool CanConvert(Type objectType)
    {
        return typeof(T).IsAssignableFrom(objectType);
    }

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

        // Create target object based on JObject
        T target = Create(objectType, jObject);

        // Populate the object properties
        serializer.Populate(jObject.CreateReader(), target);

        return target;
    }
    public override void WriteJson(
    JsonWriter writer,
    Object value,
    JsonSerializer serializer
)
    {
        throw new NotImplementedException();
    }
}
public class InputJsonConverter : JsonCreationConverter<Input>
{
    protected override Input Create(Type objectType, JObject jObject)
    {
        var type = (string)jObject.Property("Type");
        switch (type)
        {
            case "grid":
                return new GridInput();
            case "text":
                return new TextInput();
//            case "dropdown":
//                return new DropdownInput();
//            case "checkbox":
//                return new CheckboxInput();
        }

        throw new ApplicationException(String.Format("The given type {0} is not supported!", type));
    }
}
string s = @"{
    ""Id"":""e833ceae-57e5-4c52-8d56-b047790cb7c7"",
    ""Label"":""Grid time!"",
    ""Input"":
    {
        ""GridHeader"":{""ColumnDefinitionList"":[{""field"":""column1"",""title"":""Column 1""},{""field"":""column2"",""title"":""Column 2""},{""field"":""column3"",""title"":""Column 3""},{""field"":""column4"",""title"":""Column 4""}]},
        ""RowList"":
        [
            {
                ""CellList"":
                [
                    {""name"":""column1"",""Input"":{""Type"":""text"",""Value"":""cell 1 row 1""}},
                    {""name"":""column2"",""Input"":{""Type"":""text"",""Value"":""cell 2 row 1""}},
                    {""name"":""column3"",""Input"":{""Type"":""text"",""Value"":""cell 3 row 1""}},
                    {""name"":""column4"",""Input"":{""Type"":""text"",""Value"":""cell 4 row 1""}}
                ],
                ""IsDeleted"":false
            },
            {
                ""CellList"":
                [
                    {""name"":""column1"",""Input"":{""Type"":""text"",""Value"":""cell 1 row 2""}},
                    {""name"":""column2"",""Input"":{""Type"":""text"",""Value"":""cell 2 row 2""}},
                    {""name"":""column3"",""Input"":{""Type"":""text"",""Value"":""cell 3 row 2""}},
                    {""name"":""column4"",""Input"":{""Type"":""text"",""Value"":""cell 4 row 2""}}
                ],
                ""IsDeleted"":false
            }
        ],
        ""Type"":""grid"",
        ""Value"":null
    },
    ""DisplayPosition"":2,
    ""Type"":""step""
}";

【讨论】:

  • 不,如果不使用 InputJsonConverter,则会引发抽象对象反序列化错误。但是你没有用这段代码重现它的事实让我想知道我身边的一些事情,所以我会检查一下。谢谢蒂姆!
  • 好吧,我找到了罪魁祸首,正是 GridHeader 的反序列化以某种方式取消了 RowList 的反序列化......因为你的测试找到了,非常感谢 Tim :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-01
  • 1970-01-01
  • 2016-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多