我如何使用 Json.NET 反序列化 PropertyInfo?
How can I generically deserialize PropertyInfo with Json.NET?
我需要使用 Json.NET 序列化许多不同的对象。我真的无法控制所提供的对象,所以我通常使用 TypeNameHandling.All.
进行序列化和反序列化
但是,其中一些对象无法反序列化。具体来说,我得到了一些 System.Reflection.RuntimePropertyInfo 类型。我想以标准化的方式处理这些,因为在反序列化时我不知道目标类型。我也不关心,只要输出对象类型正确即可。
我尝试了 CustomCreationConverter typed to PropertyInfo that is defined in JsonSerializerSettings。但是,即使 CanConvert() 返回 true,也从未使用 CustomCreationConverter 的 ReadJson()。
最终结果就像我从未使用过 CustomCreationConverter 一样:
ISerializable type 'System.Reflection.RuntimePropertyInfo' does not
have a valid constructor. To correctly implement ISerializable a
constructor that takes SerializationInfo and StreamingContext
parameters should be present.
我需要 CustomCreationConverter 来处理 ReadJson,这样我就可以自己手动搜索 PropertyInfo。
经过更多调查,我添加到 JsonSerializerSettings 的转换器似乎根本没有被使用。如果我使用包含 JsonConverter 的类型和集合的 DeserializeObject 重载,将使用转换器。我不确定提供给 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.
}
}
}
假设 API 您需要符合必须 input/output 一个 PropertyInfo
对象,您可以删除转换器并使用新的 class 来仅保存信息需要重新创建对象。
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);
}
}
然后你可以de/serialize这样:
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);
你的例子也是如此,这就是你没有达到断点的原因。
我需要使用 Json.NET 序列化许多不同的对象。我真的无法控制所提供的对象,所以我通常使用 TypeNameHandling.All.
进行序列化和反序列化但是,其中一些对象无法反序列化。具体来说,我得到了一些 System.Reflection.RuntimePropertyInfo 类型。我想以标准化的方式处理这些,因为在反序列化时我不知道目标类型。我也不关心,只要输出对象类型正确即可。
我尝试了 CustomCreationConverter typed to PropertyInfo that is defined in JsonSerializerSettings。但是,即使 CanConvert() 返回 true,也从未使用 CustomCreationConverter 的 ReadJson()。
最终结果就像我从未使用过 CustomCreationConverter 一样:
ISerializable type 'System.Reflection.RuntimePropertyInfo' does not have a valid constructor. To correctly implement ISerializable a constructor that takes SerializationInfo and StreamingContext parameters should be present.
我需要 CustomCreationConverter 来处理 ReadJson,这样我就可以自己手动搜索 PropertyInfo。
经过更多调查,我添加到 JsonSerializerSettings 的转换器似乎根本没有被使用。如果我使用包含 JsonConverter 的类型和集合的 DeserializeObject 重载,将使用转换器。我不确定提供给 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.
}
}
}
假设 API 您需要符合必须 input/output 一个 PropertyInfo
对象,您可以删除转换器并使用新的 class 来仅保存信息需要重新创建对象。
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);
}
}
然后你可以de/serialize这样:
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);
你的例子也是如此,这就是你没有达到断点的原因。