65.9K
CodeProject 正在变化。 阅读更多。
Home

反射反序列化和自定义属性

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.81/5 (7投票s)

2016 年 2 月 17 日

CPOL
viewsIcon

29338

downloadIcon

210

反射反序列化和自定义属性。

引言

上周,我的一个同事想要将一个对象连同自定义属性一起序列化为 JSON。有趣… JSON.NET 默认情况下不允许序列化自定义属性。所以,你必须编写自定义 JSON 转换器来解决这个问题。让我们看看如何解决这个问题。

假设你拥有以下自定义属性类

    /// <summary>
    /// Complex Type Attribute
    /// </summary>
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
    public class ComplexAttribute : System.Attribute
    {
        public string Type { get; set; }
        public string DisplayName { get; set; }

    }

此外,你将其用作以下方式

    /// <summary>
    /// Creating Blog ComplexType
    /// </summary>
    [JsonConverter(typeof(ComplexTypeConverter))]
    public class Blog
    {
        [ComplexAttribute(Type = "String", DisplayName = "Blog Title")]
        public string Title { get; set; }

        [ComplexAttribute(Type = "HTML")]
        public string Content { get; set; }
    }

因此,你期望以下 JSON 序列化输出

{
"Title":{"type":"String","displayname":"Blog Title","value":"Attribute To JSON"},
"Content":{"type":"HTML","displayname":"Content",
           "value":"<p>This blog is still not implemented</p>"}
}

自定义 JsonConverter

JsonConverter 是 JSON.NET 提供的abstract 类,允许你将对象转换为 JSON 格式以及从 JSON 格式转换回来。通过继承它,你可以自定义默认的序列化和反序列化行为,如你所愿。

使用反射读取属性

属性和反射是相辅相成的。因此,当你重写 WriteJson 方法以创建自定义序列化时,你可以使用反射来读取属性值。当反序列化回对象时,我们可以以相同的方式使用反射来设置属性值。

    /// <summary>
    /// Complex type converter
    /// This class will convert attribute as JSON property
    /// </summary>
    public class ComplexTypeConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return (typeof(iComplexType).IsAssignableFrom(objectType));
        }

        public override object ReadJson
        (JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            object rootObject = Activator.CreateInstance(objectType);
            JToken objJSON = JToken.ReadFrom(reader);

            foreach (var token in objJSON)
            {
                PropertyInfo propInfo = rootObject.GetType().GetProperty
                    (token.Path, BindingFlags.IgnoreCase | BindingFlags.Public | 
                     BindingFlags.Instance);
                if (propInfo.CanWrite)
                {
                    var tk = token as JProperty;
                    if (tk.Value is JObject)
                    {
                        JValue val = tk.Value.SelectToken("value") as JValue;
                        propInfo.SetValue(rootObject, Convert.ChangeType
                         (val.Value, propInfo.PropertyType.UnderlyingSystemType), null);
                    }
                    else
                    {
                        propInfo.SetValue(rootObject, Convert.ChangeType
                          (tk.Value, propInfo.PropertyType.UnderlyingSystemType), null);
                    }
                }
            }
            return rootObject;
        }

        public override void WriteJson
           (JsonWriter writer, object value, JsonSerializer serializer)
        {
            var jo = new JObject();
            var type = value.GetType();
            foreach (PropertyInfo propInfo in type.GetProperties())
            {
                if (propInfo.CanRead)
                {
                    object propVal = propInfo.GetValue(value, null);

                    var cutomAttribute = propInfo.GetCustomAttribute<ComplexAttribute>();
                    if (cutomAttribute != null)
                    {
                        jo.Add(propInfo.Name, JToken.FromObject(new 
                              { type = cutomAttribute.Type, 
                              displayname = cutomAttribute.DisplayName ?? propInfo.Name, 
                              value = propVal ?? string.Empty }, serializer));
                    }
                    else
                    {
                        jo.Add(propInfo.Name, JToken.FromObject
                              (propVal ?? string.Empty, serializer));
                    }
                }
            }
            jo.WriteTo(writer);
        }
    }

自己尝试使用 dot net fiddle

分类于: C#, CodeProject, JSON
标签: C#, deserialization, JSON, jsonconvert, reflection, serialization

© . All rights reserved.