[英]How can I generically deserialize PropertyInfo with Json.NET?
我需要使用Json.NET序列化許多不同的對象。 我真的無法控制所提供的對象,因此通常使用TypeNameHandling.All進行序列化和反序列化。
但是,其中某些對象無法反序列化。 具體來說,我得到了一些System.Reflection.RuntimePropertyInfo類型。 我想以標准化的方式處理這些,因為在反序列化時我不知道目標類型。 只要輸出對象類型正確,我也不在乎。
我嘗試了鍵入JsonSerializerSettings中定義的PropertyCreation的CustomCreationConverter 。 但是,即使CanConvert()返回的是true,也永遠不會使用CustomCreationConverter的ReadJson()。
最終結果與我從未使用過CustomCreationConverter相同:
可ISerializable類型'System.Reflection.RuntimePropertyInfo'沒有有效的構造函數。 為了正確實現ISerializable,應該提供一個帶有SerializationInfo和StreamingContext參數的構造函數。
我需要CustomCreationConverter來處理ReadJson,以便我自己可以手動搜索PropertyInfo。
經過更多調查,看來我添加到JsonSerializerSettings中的Converter根本沒有被利用。 如果我使用包含JsonConverter的類型和集合的DeserializeObject重載,則將使用Converter。 我不確定提供給JsonSerializerSettings的Converter的用途,但是我希望它們在這種情況下可以正常工作。
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必須輸入/輸出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);
在您的示例中也是如此,這就是為什么您沒有達到斷點的原因。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.