Json数组到C#中的自定义对象映射

时间:2017-11-30 16:30:18

标签: c# arrays json

我将此JSON数组作为输入。

[
    {
        "FirstName": "Test1",
        "LastName": "Test2",
        "Address": "London, GB",
        "Error": "Something's gone wrong"
    },
    {
        "FirstName": "Test3",
        "LastName": "Test4",
        "Address": "NewYork, US",
        "Error": "Something's gone wrong"
    },
    {
        "DisplayName": "ContactNumber",
        "Value": "01234 123 123"
    }
]

我想在C#

中构建一个像这样的JSON对象
[
    "pages":{
        "FirstName": "Test1",
        "LastName": "Test2",
        "Address": "London, GB",
        "Error": "Something's gone wrong"
    },
    {
        "FirstName": "Test3",
        "LastName": "Test4",
        "Address": "NewYork, US",
        "Error": "Something's gone wrong"
    },
  "labels": {
        "DisplayName": "ContactNumber",
        "Value": "01234 123 123"
  }
}
]

我创建了一个具有上述输出属性的模型,但是当我将对象反序列化为该模型时,它们没有被映射。所有值都返回null。

var deserializedData = JsonConvert.DeserializeObject<List<Config>>(serializedData);

我检查时收到的回复是

[
    {
        "pages": null,
        "labels": null
    },
    {
        "pages": null,
        "labels": null
    }
]

任何人都可以帮助我在 C#中为我想要的格式构建自定义模型

提前致谢。

2 个答案:

答案 0 :(得分:0)

你的json是无效的json结构进行解析,这根本无效(请在这里检查它有什么问题:https://jsonlint.com/

无效的json字符串

[
    "pages":{
        "FirstName": "Test1",
        "LastName": "Test2",
        "Address": "London, GB",
        "Error": "Something's gone wrong"
    },
    {
        "FirstName": "Test3",
        "LastName": "Test4",
        "Address": "NewYork, US",
        "Error": "Something's gone wrong"
    },
  "labels": {
        "DisplayName": "ContactNumber",
        "Value": "01234 123 123"
  }
}
]

但是我给你修好了json

修复并正常工作json

[{
    "pages": [{
            "FirstName": "Test1",
            "LastName": "Test2",
            "Address": "London, GB",
            "Error": "Something's gone wrong"
        },
        {
            "FirstName": "Test3",
            "LastName": "Test4",
            "Address": "NewYork, US",
            "Error": "Something's gone wrong"
        }
    ],
    "labels": {
        "DisplayName": "ContactNumber",
        "Value": "01234 123 123"
    }
}]

应用修复json后,您的C#对象

public class Page
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address { get; set; }
    public string Error { get; set; }
}

public class Labels
{
    public string DisplayName { get; set; }
    public string Value { get; set; }
}

public class RootObject
{
    public List<Page> pages { get; set; }
    public Labels labels { get; set; }
}

我尝试使用我的固定json并且工作正常。

编辑结束

下面的代码对我来说很合适,我在下面提供了类结构

列表

var jsonString = "[{ \"pages\": {\"id\": 12345, \"name\": \"John Doe\", \"number\": \"123\", \"test\": "+
 "\"John\" }, \"labels\": { \"test\": \"test1\", \"test2\": \"test2\" } }," +
                            "{ \"pages\": {\"id\": 12345, \"name\": \"John Doe\", \"number\": \"123\", \"test\": "+
 "\"John\" }, \"labels\": { \"test\": \"test1\", \"test2\": \"test2\" } }]";

var deserializedData = JsonConvert.DeserializeObject<List<RootObject>>(jsonString);

以单个对象作为输入

var jsonString = "{ \"pages\": {\"id\": 12345, \"name\": \"John Doe\", \"number\": \"123\", \"test\": "+
 "\"John\" }, \"labels\": { \"test\": \"test1\", \"test2\": \"test2\" } }";

 var deserializedData = JsonConvert.DeserializeObject<RootObject>(jsonString);

基于输入

{ "pages": { "id": 12345, "name": "John Doe", "number": "123", "test": 
 "John" }, "labels": { "test": "test1", "test2": "test2" } }

下面是生成的类

public class Pages
{
    public int id { get; set; }
    public string name { get; set; }
    public string number { get; set; }
    public string test { get; set; }
}

public class Labels
{
    public string test { get; set; }
    public string test2 { get; set; }
}

public class RootObject
{
    public Pages pages { get; set; }
    public Labels labels { get; set; }
}

如果你有Json,那么你可以使用visual studio本身生成C#类。

在视觉工作室中查找&#34;粘贴Sepcial&#34;菜单。即复制json字符串并单击Paste special,它将为您生成C#类。

您可以关注我的帖子:Generate Class From JSON or XML in Visual Studio

enter image description here

或使用以下在线网站:json2csharp

答案 1 :(得分:0)

您所拥有的是包含各种类型对象的多态JSON数组,可通过特定属性("DisplayName" vs "FirstName"的存在来区分,例如)。您想要做的是将其反序列化为c#模型,其中每个可能的数组项都被添加到模型的集合值属性中,其中选择集合属性以具有正确的项类型。

这可以通过使用custom JsonConverter来完成。由于问题陈述是通用的,我将使转换器成为通用的。硬编码转换器需要的代码更少。

首先,按如下方式定义您想要的模型:

public class Page
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address { get; set; }
    public string Error { get; set; }
}

public class Label
{
    public string DisplayName { get; set; }
    public string Value { get; set; }
}

public class RootObject
{
    public List<Page> pages { get; set; }
    public List<Label> labels { get; set; }
}

接下来定义以下转换器:

public class PolymorphicArrayToObjectConverter<TObject> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(TObject).IsAssignableFrom(objectType);
    }

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

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

    static JsonObjectContract FindContract(JObject obj, IEnumerable<Type> derivedTypes, JsonSerializer serializer)
    {
        List<JsonObjectContract> bestContracts = new List<JsonObjectContract>();
        foreach (var type in derivedTypes)
        {
            if (type.IsAbstract)
                continue;
            var contract = serializer.ContractResolver.ResolveContract(type) as JsonObjectContract;
            if (contract == null)
                continue;
            if (obj.Properties().Select(p => p.Name).Any(n => contract.Properties.GetClosestMatchProperty(n) == null))
                continue;
            if (bestContracts.Count == 0 || bestContracts[0].Properties.Count > contract.Properties.Count)
            {
                bestContracts.Clear();
                bestContracts.Add(contract);
            }
            else if (contract.Properties.Count == bestContracts[0].Properties.Count)
            {
                bestContracts.Add(contract);
            }
        }
        return bestContracts.Single();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        else if (reader.TokenType != JsonToken.StartArray)
            throw new InvalidOperationException("JSON token is not an array at path: " + reader.Path);

        var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(objectType);
        existingValue = existingValue ?? contract.DefaultCreator();

        var lookup = contract
            .Properties
            .Select(p => new { Property = p, PropertyContract = serializer.ContractResolver.ResolveContract(p.PropertyType) as JsonArrayContract })
            .Where(i => i.PropertyContract != null)
            .ToDictionary(i => i.PropertyContract.CollectionItemType);
        var types = lookup.Select(i => i.Key).ToList();

        while (reader.Read())
        {
            switch (reader.TokenType)
            {
                case JsonToken.Comment:
                    break;
                case JsonToken.EndArray:
                    return existingValue;
                default:
                    {
                        var itemObj = JObject.Load(reader);
                        var itemContract = FindContract(itemObj, types, serializer);
                        if (itemContract == null)
                            continue;
                        var item = serializer.Deserialize(itemObj.CreateReader(), itemContract.UnderlyingType);
                        var propertyData = lookup[itemContract.UnderlyingType];
                        var collection = propertyData.Property.ValueProvider.GetValue(existingValue);
                        if (collection == null)
                        {
                            collection = propertyData.PropertyContract.DefaultCreator();
                            propertyData.Property.ValueProvider.SetValue(existingValue, collection);
                        }
                        collection.GetType().GetMethod("Add").Invoke(collection, new [] { item });
                    }
                    break;
            }
        }
        // Should not come here.
        throw new JsonSerializationException("Unclosed array at path: " + reader.Path);
    }
}

然后,反序列化并重新序列化您的RootObject集合,如下所示:

var settings = new JsonSerializerSettings
{
    Converters = { new PolymorphicArrayToObjectConverter<RootObject>() },
};
var root = new List<RootObject> { JsonConvert.DeserializeObject<RootObject>(jsonString, settings) };

var outputJson = JsonConvert.SerializeObject(root, Formatting.Indented);

结果,将生成以下JSON:

[
  {
    "pages": [
      {
        "FirstName": "Test1",
        "LastName": "Test2",
        "Address": "London, GB",
        "Error": "Something's gone wrong"
      },
      {
        "FirstName": "Test3",
        "LastName": "Test4",
        "Address": "NewYork, US",
        "Error": "Something's gone wrong"
      }
    ],
    "labels": [
      {
        "DisplayName": "ContactNumber",
        "Value": "01234 123 123"
      }
    ]
  }
]

示例fiddle

注 - 自动推断数组项类型的代码改编自this answer