JSON.NET 使用技巧

1. 序列化相關技巧

經過特性忽略某些屬性html

有時候咱們會有這樣的需求,咱們只須要序列化實體類中的一部分屬性,這時候咱們能夠經過聲明忽略掉一些咱們不須要序列化的屬性,有兩種方式可使用麼達到這個目標:express

首先,能夠考慮使用JsonIgnore特性修飾不須要進行序列化的屬性,以下所示:json

public class EmployeeBean
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public decimal Salary { get; set; }
    public string Phone { get; set; }
    [JsonIgnore]
    public DateTime HireDate { get; set; }
}

運行程序:安全

var employeeBean = new EmployeeBean()
{
    Id = Guid.NewGuid(),
    Name = "gyzhao",
    Email = "gyzhao@gyzhao.com",
    Salary = 10000,
    Phone = "13912390987",
    HireDate = new DateTime(2012, 2, 1)
};
    
var jsonString = JsonConvert.SerializeObject(employeeBean, Formatting.Indented);
//輸出:
//{
//  "Id": "69a406ad-902c-45d3-8ba7-89a09779ed52",
//  "Name": "gyzhao",
//  "Email": "gyzhao@gyzhao.com",
//  "Salary": 10000.0,
//  "Phone": "13912390987"
//}

若是說你須要序列化的類有不少的屬性,而你是須要使用其中的一小部分,若是使用上面的上面方式就會比較繁瑣(由於須要忽略的屬性太多了),這時候能夠考慮使用DataContract特性修飾被序列化的類,使用DataMember特性修飾須要進行序列化的屬性,其餘沒有該特性屬性會被自動忽略掉。以下所示:ide

[DataContract]
public class EmployeeBean
{
    [DataMember]
    public Guid Id { get; set; }
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public string Email { get; set; }
    [DataMember]
    public decimal Salary { get; set; }
    public string Phone { get; set; }

    public DateTime? HireDate { get; set; }
}

運行程序:函數

var employeeBean = new EmployeeBean()
{
    Id = Guid.NewGuid(),
    Name = "gyzhao",
    Email = "gyzhao@gyzhao.com",
    Salary = 10000,
    Phone = "13912390987",
    HireDate = new DateTime(2012, 2, 1)
};
    
var jsonString = JsonConvert.SerializeObject(employeeBean, Formatting.Indented);
//輸出:
//{
//  "Id": "69a406ad-902c-45d3-8ba7-89a09779ed52",
//  "Name": "gyzhao",
//  "Email": "gyzhao@gyzhao.com",
//  "Salary": 10000.0
//}

DataContract特性和DataMember特性都從屬於: System.Runtime.Serialization命名空間。oop

動態序列化對象屬性ui

多謝園友 @夜色、花清淺 的提醒,確實有這樣的場景:更多的咱們可能須要的是動態的來肯定須要序列化哪些屬性,好比對於EmployeeBean來講:A方法須要序列化 NameId 屬性,而 B方法須要序列化 EmailPhone 屬性,在這種狀況下,前面的兩種使用特性的方式並不能很好的適應需求的變化,經過查詢 JSON.NET 的文檔(傳送門:Json.NET Documentation),官方文檔提供了這個API的示例程序,下面是改進的示例:this

var employeeBean = new EmployeeBean()
{
    Id = Guid.NewGuid(),
    Name = "gyzhao",
    Email = "gyzhao@gyzhao.com",
    Salary = 10000,
    Phone = "13912390987",
    HireDate = new DateTime(2015, 5, 4)
};

var perperties = new List<string>()
{
    employeeBean.GetPropertyName(t => t.Email),
    employeeBean.GetPropertyName(t => t.Phone)
};

var jsonString = JsonConvert.SerializeObject(employeeBean, Formatting.Indented, new JsonSerializerSettings()
{
    ContractResolver = new JsonDynamicContractResolver(perperties)
    });

//{
//  "Email": "gyzhao@gyzhao.com",
//  "Phone": "13912390987"
//}
Console.WriteLine(jsonString);

下面是定義 JsonDynamicContractResolver 類的定義:編碼

public class JsonDynamicContractResolver : DefaultContractResolver
{  
    private readonly List<string> _propertiesList; 
    public JsonDynamicContractResolver(IEnumerable<string> propertiesEnumerable)
    {
        if (propertiesEnumerable != null)
        {
            _propertiesList = propertiesEnumerable.ToList();
        }
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);

        //只序列化構造器中傳入的包含在字符串中的屬性
        if (_propertiesList != null && _propertiesList.Any())
        {
            properties =
            properties.Where(p => _propertiesList.Exists(pString => pString == p.PropertyName)).ToList();
        }
        return properties;
    }
}

在 傳入 JsonDynamicContractResolver 構造函數中的指定序列化屬性的集合時,我在這裏使用了擴展方法:GetPropertyName ,這個方法經過傳入一個 Lambda 表達式來獲取須要序列化屬性的字符串表示,這裏是經過表達式樹來實現的。相對於直接硬編碼屬性名稱的字符串來講,使用表達式樹動態獲取在效率上有所損失(可接受的程度),不過換取的是設計上的靈活。好比:當咱們更改屬性名稱時,編譯器能夠爲咱們提供類型安全的保護。而若是硬編碼的話,若是一旦忘記修改,那麼運行就會拋出異常,特別是系統中若是有不少地方都是用這種硬編碼方式的話,那麼維護起來就是一個噩夢了。下面是該擴展方法的代碼:

public static class Extensions
{

    /// <summary>
    /// 獲取對象實例屬性的字符串表示
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="obj"></param>
    /// <param name="func"></param>
    /// <returns></returns>
    public static string GetPropertyName<T>(this T obj, Expression<Func<T, object>> func)
    {
        var propertyName = string.Empty;
        var expression = func.Body as UnaryExpression;
        if (expression != null)
        {
            propertyName = ((MemberExpression) expression.Operand).Member.Name;
        }
        else
        {
            var memberExpression = func.Body as MemberExpression;
            if (memberExpression != null)
            {
                propertyName = memberExpression.Member.Name;
            }
            else
            {
                var body = func.Body as ParameterExpression;
                if (body != null)
                {
                    propertyName = body.Type.Name;
                }
            }
        }
        return propertyName;
    }
}

序列化對象時循環引用異常的解決辦法

序列化一個對象時,若是該對象有一個集合屬性,改集合的類型就是對象自己的話,默認序列化的方法會報一個循環引用的異常,若是須要序列化,只需聲明下面的屬性便可:

JsonConvert.SerializeObject(result,new JsonSerializerSettings{ReferenceLoopHandling=ReferenceLoopHandling.Serialize})

2. 反序列化相關技巧

2.1 使用匿名類型做爲反序列化實體

var jsonString = @"{
                    'Id': '69a406ad-902c-45d3-8ba7-89a09779ed52',
                    'Name': 'gyzhao',
                    'Salary': 10000.0,
                    'HireDate': '2012-02-01T00:00:00'
                   }";
var employee = new
                {
                    Name = default(string),
                    Salary = default(decimal),
                    HireDate = default(DateTime),
                    Id = default(Guid)
                };
var employeeBean = JsonConvert.DeserializeAnonymousType(jsonString, employee);

3. 建立JSON

//命令式的建立JSON對象
var array = new JArray();
var text = new JValue("Manual text");
var date = new JValue(DateTime.Now);

array.Add(text);
array.Add(date);

Console.WriteLine(array.ToString());

//使用聲明式的語法
var rss =
    new JObject(
        new JProperty("channel", new JObject(
            new JProperty("title", "James Nexton-king"),
            new JProperty("link", "http://james.newtonking.com"),
            new JProperty("description", "James Newton-Kin's blog."),
            new JProperty("item", "BB"))));
Console.WriteLine(rss.ToString());

//經過一個匿名對象建立JSON
JObject o = JObject.FromObject(new
{
    channel = new
    {
        title = "James Newton-king",
        link = "http://james.netwoing.com",
        item = new List<string>()
        {
            "A",
            "B",
            "C",
            "D",
            "E"
        }
    }
});
Console.WriteLine(o.ToString());

參考&進一步閱讀

http://www.newtonsoft.com/json

相關文章
相關標籤/搜索