2015-03-18 42 views
4

我需要使用Json.NET序列化许多不同的对象。我真的无法控制所提供的对象,所以我通常会使用TypeNameHandling.All进行序列化和反序列化。我怎样才能一般反序列PropertyInfo与Json.NET?

但是,其中一些对象不能被反序列化。具体来说,我得到一些System.Reflection.RuntimePropertyInfo类型。我想以标准化的方式处理这些问题,因为我在反序列化时没有意识到目标类型。只要输出对象类型正确,我也不在乎。

我试过CustomCreationConverter输入到PropertyInfo中,该属性在JsonSerializerSettings中定义。但是,即使CanConvert()返回true,CustomCreationConverter的ReadJson()也不会被使用。

最终的结果是一样的,如果我从来没有使用过的CustomCreationConverter:

ISerializable的类型“System.Reflection.RuntimePropertyInfo”不 有一个有效的构造。要正确实现ISerializable,需要带有Seri​​alizationInfo和StreamingContext 参数的构造函数应该存在。

我需要CustomCreationConverter来处理ReadJson,以便我可以自己手动搜索PropertyInfo。

经过更多的调查后,似乎我添加到JsonSerializerSettings的转换器根本没有被利用。如果我使用包含JsonConverter类型和集合的DeserializeObject重载,则将使用Converter。我不确定转换器提供给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. 
     } 
    } 
} 
+2

为什么你需要序列化整个PropertyInfo对象?属性名称不够?这可能是困难和棘手的PropertyInfo引用类型和类型引用程序集和程序集有很多不同的引用到其他对象... – 2015-03-18 22:06:18

+0

特别是这是为一个新的缓存提供程序注入一个非常古老的遗留系统。序列化是新提供者缓存引擎的要求。就缓存访问而言,提供者必须逐字复制以前的提供者的功能。 – 2015-03-18 22:12:58

+0

也许你应该提到异常'ISerializable类型'System.Reflection.RuntimePropertyInfo'没有一个有效的构造函数。要正确实现ISerializable,需要带有Seri​​alizationInfo和StreamingContext参数的构造函数。路径'',第1行,第287位。' – 2015-03-18 22:15:56

回答

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(); 

这里是一个真正的原油(read方法并不是很稳定),例如使用一个转换器,以及:

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); 

在你的例子中也是如此,这就是为什么你没有达到你的折点。

+0

有趣的是,包裹罪犯,以避免直接序列化,而不是使用自定义转换器。我假设然后处理泛型类型,它只是对任一方向进行类型检查并适当地处理它。 – 2015-07-06 18:08:57

+0

如果我需要一个转换器,我会在转换器内部使用类似的代码。使用“CustomCreationConverter”的方式会遇到问题,因为在Create方法中,您没有足够的信息来可靠地创建一个PropertyInfo实例。它是抽象的,你很可能序列化一个不是公共的“RuntimePropertyInfo”实例。相反,我会继承'JsonConverter'类。如果您想继续使用默认序列化,请覆盖'CanWrite'属性并始终返回false。 – Sacrilege 2015-07-06 22:50:02