How can I generally deserialize PropertyInfo using Json.NET?

I need to serialize many different objects using Json.NET. I really do not control the objects provided, so I generalize and de-serialize with TypeNameHandling.All .

However, some of these objects cannot be de-serialized. In particular, I get some types of System.Reflection.RuntimePropertyInfo. I would like to handle them in a standardized way, since I did not know about the type of target during de-serialization. I also don't care if the type of output object is correct.

I tried to execute a CustomCreationConverter introduced in PropertyInfo, which is defined in JsonSerializerSettings . However, although CanConvert () returns true, CustomCreationConverter ReadJson () is never used.

The end result is the same as if I had never used a CustomCreationConverter:

The ISerializable type 'System.Reflection.RuntimePropertyInfo' does not support have a valid constructor. To correctly implement ISerializable, a constructor that accepts SerializationInfo and StreamingContext parameters must be present.

I need a CustomCreationConverter to handle ReadJson so that I can manually manually search for PropertyInfo.

, , JsonSerializerSettings, . DeserializeObject, JsonConverter, . , , JsonSerializerSettings, , , , .

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;

namespace Json
{
    class Program
    {
        static void Main(string[] args)
        {
            var jsonSerializerSettings = new JsonSerializerSettings()
            {
                TypeNameHandling = TypeNameHandling.All,
                TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple,
                Converters = new JsonConverter[] { new PropertyInfoConverter(), },
            };
            var propertyInfo = typeof(Test).GetProperty("Name");

            var serialized = JsonConvert.SerializeObject(propertyInfo, jsonSerializerSettings);
            var deserialized = JsonConvert.DeserializeObject(serialized, jsonSerializerSettings);
        }
    }

    public class Test
    {
        public string Name { get; set; }
    }

    public class PropertyInfoConverter : CustomCreationConverter<PropertyInfo>
    {
        public override bool CanConvert(Type objectType)
        {
            return typeof(PropertyInfo).IsAssignableFrom(objectType);
        }

        public override PropertyInfo Create(Type objectType)
        {
            return null;
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            return null; // This is never invoked, but is where I would attempt to find the PropertyInfo via Reflection searching.
        }
    }
}
+4
1

, API, , / PropertyInfo, , .

private class PropertyInfoData
{
    public string TypeName
    {
        get;
        set;
    }

    public string PropertyName
    {
        get;
        set;
    }

    public static PropertyInfoData FromProperty(PropertyInfo p)
    {
        return new PropertyInfoData()
        {
            TypeName = p.DeclaringType.AssemblyQualifiedName,
            PropertyName = p.Name,
        };
    }

    public PropertyInfo ToProperty()
    {
        return Type.GetType(this.TypeName).GetProperty(this.PropertyName);
    }
}

/ :

var jsonSerializerSettings = new JsonSerializerSettings()
{
    TypeNameHandling = TypeNameHandling.All,
    TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple,
    //Converters = new JsonConverter[] { new PropertyInfoConverter(), },
};
var propertyInfo = typeof(Test).GetProperty("Name");

var serialized = JsonConvert.SerializeObject(PropertyInfoData.FromProperty(propertyInfo), jsonSerializerSettings);
var deserialized = ((PropertyInfoData)JsonConvert.DeserializeObject(serialized, jsonSerializerSettings)).ToProperty();

( ), , :

public class PropertyInfoConverter : JsonConverter
{
public override bool CanWrite
{
    get
    {
        return false;
    }
}

public override bool CanConvert(Type objectType)
{
    return typeof(PropertyInfo).IsAssignableFrom(objectType);
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    string propertyName = null;
    string assemblyName = null;
    string typeName = null;

    while (reader.Read())
    {
        if (reader.TokenType == JsonToken.PropertyName)
        {
            string value = reader.Value.ToString();

            switch (reader.Value.ToString())
            {
                case "Name":
                    if (reader.Read())
                    {
                        propertyName = reader.Value.ToString();
                    }
                    break;
                case "AssemblyName":
                    if (reader.Read())
                    {
                        assemblyName = reader.Value.ToString();
                    }
                    break;
                case "ClassName":
                    if (reader.Read())
                    {
                        typeName = reader.Value.ToString();
                    }
                    break;
            }
        }       
    }

    return Type.GetType(typeName + ", " + assemblyName).GetProperty(propertyName);
}

/// <inheritdoc />
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    // When the property "CanWrite" returns false this method is never expected to be called.
    throw new NotImplementedException();
}

}

. , :

var deserialized = JsonConvert.DeserializeObject<PropertyInfo>(serialized, jsonSerializerSettings);

, .

+1

All Articles