Newtonsoft.Json使用
序列化与反序列化
1、反序列化是不区分大小写的
以下代码可以正常运行
public static void Test() { //反序列化时 不区分大小写的 string jsonString = "{\"name\":\"张三\",\"age\":18,\"sex\":\"男\"}"; var model = JsonConvert.DeserializeObject<PersonJson>(jsonString); if (model != null) { Console.WriteLine(model.Name); } } public class PersonJson { public string Name { get; set; } public int Age { get; set; } public string Sex { get; set; } }
2、序列化
若想不区分大小写,参考:使用Newtonsoft.Json进行Json序列化忽略首字母大小写,Json字符串反序列化到子集对象(C#)
JObject 用法 、JProperty 用法、JArray 用法
使用LINQ to JSON前,需要引用Newtonsoft.Json的dll和using Newtonsoft.Json.Linq的命名空间。
LINQ to JSON主要使用到JObject, JArray, JProperty和JValue这四个对象,
- JObject用来生成一个JSON对象,简单来说就是生成”{}”,
- JArray用来生成一个JSON数组,也就是”[]”,
- JProperty用来生成一个JSON数据,格式为key/value的值,
- 而JValue则直接生成一个JSON值
简单示例:
JArray jo1 = (JArray)JsonConvert.DeserializeObject(JsonConvert.SerializeObject(list)); JObject a1 = (JObject)resultJson["group"][times]; a1.Add(new JProperty("list", jo1));
参考:
问题
1、平方² 保存到文件变成了2
var test =new {name ="速度(m/²)"};
注意: File.WriteAllText()是,编码要设置为Encoding.UTF8,而不能是Default。
2、json字符串和 对象(复杂对象) 相互解析时,字段一一匹配的问题
2.1 MissingMemberHandling可以解决 对象中缺少 Json字符串中定义的字段
并通过使用`JsonExtensionData`特性和`Dictionary<string, JToken>`类来捕获未解析的JSON属性
JsonSerializerSettings jss = new JsonSerializerSettings(); jss. MissingMemberHandling = MissingMemberHandling.Error; string json = Newtonsoft.Json.JsonConvert.SerializeObject(obj, Formatting.Indented, jss);
使用`Newtonsoft.Json`将字符串转换为对象时,确保对象中的所有字段在字符串中都能找到的写法是在`DeserializeObject`方法的第二个参数中添加一个`JsonSerializerSettings`对象,并将其`MissingMemberHandling`属性设置为`MissingMemberHandling.Error`。这样,当字符串中的字段没有对应到对象的属性时,将会抛出异常。
以下是示例代码:
```csharp
using Newtonsoft.Json;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
string json = @"{""Name"":""Tom"",""Age"":30,""Gender"":""male""}"; // 假设字符串中有一个未定义的 Gender 字段
JsonSerializerSettings settings = new JsonSerializerSettings
{
MissingMemberHandling = MissingMemberHandling.Error // 指定 MissingMemberHandling 属性为 Error
};
Person person = JsonConvert.DeserializeObject<Person>(json, settings); // 进行字符串转换为对象
```
在此示例中,我们定义了一个`Person`类,并初始化了一个包含未定义的`Gender`字段的JSON字符串。在调用`DeserializeObject`方法时,我们将第二个参数`settings`设置为一个包含`MissingMemberHandling`属性的`JsonSerializerSettings`对象,并将其值设置为`MissingMemberHandling.Error`,这将会在字符串中有未定义字段的情况下引发异常。最后,我们调用`DeserializeObject`方法将JSON字符串转换为`Person`对象,如果字符串中包含未定义字段,则会引发异常。
可以捕获哪些没有 解析的字段:
如果对象中的字段比字符串中的字段多,可以创建`JsonSerializerSettings`对象,并将其`MissingMemberHandling`属性设置为`MissingMemberHandling.Error`。这将会在反序列化过程中引发异常,以指示缺少的成员或JSON属性。
另一种方法是使用`JsonExtensionData`特性和`Dictionary<string, JToken>`类来捕获未解析的JSON属性。使用`JsonExtensionData`特性和`Dictionary<string, JToken>`类,可以在定义时不需要知道有哪些未解析的JSON属性(因为它们存储在字典中)。
【这种方式 只能检测:字符串比对象多的情况,字符串中多了的会放在 ,字典中】
以下是示例代码:
```csharp
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
[JsonExtensionData]
private IDictionary<string, JToken> additionalProperties;
public void Validate()
{
if (additionalProperties != null && additionalProperties.Count > 0)
{
throw new JsonSerializationException(string.Format("未解析的 JSON 属性: {0}", string.Join(",", additionalProperties.Keys)));
}
}
}
string json = @"{""Name"":""Tom"",""Age"":30,""Gender"":""male""}"; // 字段 "Gender" 对象中未定义
JsonSerializerSettings settings = new JsonSerializerSettings
{
MissingMemberHandling = MissingMemberHandling.Error // 设置 MissingMemberHandling 属性
};
Person person = JsonConvert.DeserializeObject<Person>(json, settings); // 进行反序列化
person.Validate(); // 检查格式是否正确
```
在此示例中,我们定义了一个`Person`类,用于存储JSON对象的属性。在这个类中,我们将`additionalProperties`字段使用`JsonExtensionData`特性标记为扩展数据。当使用`DeserializeObject`方法将JSON字符串转换为`Person`对象时,所有未在类定义中列出的属性都将存储在`additionalProperties`字典中。我们定义了一个`Validate`方法来检查`additionalProperties`字段,并在其中引发异常,如果检查失败。
2.2 结合JsonProperty
特性和Required
属性,解决 Json中缺少 对象中定义的字段
需要结合JsonProperty
特性和Required
属性来解决。使用JsonProperty
特性可以映射Json字典中的属性名,同时,可以使用Required
属性,它会强制要求在 JSON 字典中具有指定的属性。只要Required
属性将其设置为true
,则在反序列化过程中如果缺少其对应的属性,则会抛出异常。
using Newtonsoft.Json; public class Person { public string Name { get; set; } public int Age { get; set; } [JsonProperty(Required = Required.Always)] public Student Std { get; set; } } public class Student { public int Id { get; set; } [JsonProperty(Required = Required.Always)] public int Parent { get; set; } } string json = @"{""Name"":""Tom"",""Age"":30,""Std"":{""Id"":12}}"; // 缺少 "Parent" 属性 Person person = JsonConvert.DeserializeObject<Person>(json); // 进行反序列化
在此示例中,我们在Person
类和Student
类的属性上分别使用了JsonProperty
和Required
属性。Required
属性的值设置为Required.Always
,表示在JSON字符串中必须包含此属性。由于JSON字符串缺少Parent
属性,当我们使用JsonConvert.DeserializeObject
方法将JSON字符串转换为Person
对象时,将抛出异常。
总之,使用JsonProperty
特性和Required
属性可以解决JSON字符串中少字段的问题,确保在反序列化时字段一一匹配,缺失的部分会报错。
2.3 对所有 属性打特性
假如一个复杂对象有上百个字段,所有字段都需要注明[JsonProperty(Required = Required.Always)],该如何写?
如果一个复杂对象有很多字段,每个字段都需要使用`[JsonProperty(Required = Required.Always)]`特性来强制要求在 JSON 字典中有对应的属性,那么我们可以使用属性标记器来对所有的属性进行统一标记。具体步骤如下:
1.定义一个自定义特性,用于在所有属性上注明`[JsonProperty(Required = Required.Always)]`特性:
```csharp
[AttributeUsage(AttributeTargets.Property)]
public class RequiredJsonPropertyAttribute : Attribute { }
```
2.在所有要求强制要求在 JSON 字典中有对应的属性的属性上,标记自定义特性,如下所示:
```csharp
public class Person
{
[RequiredJsonProperty]
public string Name { get; set; }
[RequiredJsonProperty]
public int Age { get; set; }
[RequiredJsonProperty]
public Student Std { get; set; }
// ...
}
```
3.在反序列化对象之前,使用反射来为所有打了标记的属性添加`[JsonProperty(Required = Required.Always)]`特性,具体实现如下:
```csharp
using Newtonsoft.Json;
using System.Linq;
using System.Reflection;
public class MyJsonConverter : JsonConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
object instance = Activator.CreateInstance(objectType);
PropertyInfo[] properties = objectType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo property in properties)
{
RequiredJsonPropertyAttribute attribute = property.GetCustomAttribute<RequiredJsonPropertyAttribute>();
if (attribute != null)
{
JsonPropertyAttribute jsonAttribute = property.GetCustomAttributes(true).OfType<JsonPropertyAttribute>().FirstOrDefault();
if (jsonAttribute == null)
{
jsonAttribute = new JsonPropertyAttribute();
}
jsonAttribute.Required = Required.Always;
property.SetCustomAttribute(jsonAttribute);
}
}
serializer.Populate(reader, instance);
return instance;
}
public override bool CanConvert(Type objectType)
{
return true;
}
public override bool CanWrite
{
get { return false; }
}
}
```
以下是使用示例:
```csharp
string json = @"{""Name"":""Tom"",""Age"":30,""Std"":{""Id"":12}}"; // 缺少 "Parent" 属性
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.Converters.Add(new MyJsonConverter());
Person person = JsonConvert.DeserializeObject<Person>(json, settings); // 进行反序列化
```
在此示例中,我们首先定义了一个名为`RequiredJsonPropertyAttribute`的自定义特性,并将其用于在所有应强制要求在JSON字典中具有相应属性的属性上。然后,我们创建了一个派生自`JsonConverter`的自定义JSON转换器,名为`MyJsonConverter`。在`ReadJson`方法中,我们通过反射遍历所有打了特性标记`[RequiredJsonProperty]`的属性,并添加到`[JsonProperty(Required = Required.Always)]`特性中来强制要求在JSON字典中存在相应的属性。最后,使用`settings.Converters.Add`方法将`MyJsonConverter`对象添加到`JsonConvert.DeserializeObject`方法的设置参数中。
总之,使用自定义特性与反射技术,可以用这种方式轻松地为所有复杂对象的属性添加`[JsonProperty(Required = Required.Always)]`特性,确保在反序列化时字段一一匹配,缺失的部分会报错。