JSON.NETテクニック

8417 ワード

1.シーケンス化に関するテクニック
プロパティによって一部のプロパティを無視する
時には、エンティティクラスの一部の属性をシーケンス化する必要があります.この場合、シーケンス化を必要としない属性を無視することを宣言します.この目標を達成するには、次の2つの方法があります.
まず、以下に示すように、JsonIgnoreの特性修飾を用いてシーケンス化を必要としない属性を考慮することができる.
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 = "[email protected]",
    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": "[email protected]",
//  "Salary": 10000.0,
//  "Phone": "13912390987"
//}

シーケンス化が必要なクラスには多くの属性がありますが、その一部を使用する必要があります.上記の方法を使用すると煩雑になります(無視する必要がある属性が多すぎるため).この場合、DataContractの特性を使用してシーケンス化されたクラスを修飾し、DataMemberの特性を使用してシーケンス化が必要な属性を修飾することを考慮することができます.このプロパティがない他のプロパティは自動的に無視されます.次のようになります.
[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 = "[email protected]",
    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": "[email protected]",
//  "Salary": 10000.0
//}
DataContractプロパティとDataMemberプロパティは、System.Runtime.Serializationネーミングスペースに従属します.
ダイナミックシーケンス化オブジェクトのプロパティ
園友@夜色、花清浅の注意に感謝して、確かにこのようなシーンがあります:もっと多くの私たちが必要とするのは動的にどの属性をシーケンス化する必要があるかを決定することです.例えば、EmployeeBeanにとって:A方法はNameIdの属性をシーケンス化する必要がありますが、B方法はEmailPhoneの属性をシーケンス化する必要があります.この場合、前の2つの使用特性の方式は需要の変化によく適応できず、JSONを検索する.NETのドキュメント(転送ゲート:Json.NET Documentation)、公式ドキュメントはこのAPIの例示的なプログラムを提供し、以下は改善された例である.
var employeeBean = new EmployeeBean()
{
    Id = Guid.NewGuid(),
    Name = "gyzhao",
    Email = "[email protected]",
    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": "[email protected]",
//  "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