我正在使用Newtonsoft json.net序列化程序将我的一些模型序列化为json。
其中一些是复杂的,包含循环引用。由于循环引用不可序列化,因此设置为ReferenceLoopHandling = ReferenceLoopHandling.Ignore
。
使用ISupportInitialize进行其他序列化后,将恢复引用。
ISupportInitialize还用于初始化数据库中的重属性(图像)。有些类没有默认的ctor(需要[NotNull]参数),我知道我的重属性可能很懒,但由于我的ISupportInitialize与以前的序列化程序一样正常(并且经过测试),我会优先使用该机制。
我正在尝试让json.net序列化程序检测实现ISupportInitialize接口的类型并调用相应的接口方法。当实际的序列化/反序列化对象实现接口时,这很简单,但当对象图中的某个属性实现它时,它更难(或者至少对我来说不直观)。我试过写一个自定义转换器,但没有运气。以下是我想要完成的一个简单示例
public class SupportsInitialize : ISupportInitialize
{
public void BeginInit(){throw new NotImplementedException();}
public void EndInit(){throw new NotImplementedException();}
}
[Test]
public void MakeSerializerCallBeginAndEndInit()
{
var supportsInitialize = new ToBeSerialized() {SupportsInitialize = new SupportsInitialize()};
// before serializing any property implementing ISupportInitialize (ToBeSerialized.SupportsInitialize in this case) its BeginInit should be called
var json = JsonConvert.SerializeObject(supportsInitialize);
// after deserializing any property implementing ISupportInitialize its EndInit should be called
var deserialized = JsonConvert.DeserializeObject<ToBeSerialized>(json);
}
public class ToBeSerialized
{
public SupportsInitialize SupportsInitialize { get; set; }
}
Thanx帮助我指明正确的方向
答案 0 :(得分:2)
如果您不想手动添加BeginInit()
和EndInit()
来自[OnDeserializing]
and [OnDeserialized]
类型的ISupportInitialize
回调,则可以创建自定义子类自动调用适当方法的DefaultContractResolver
:
public class ISupportInitializeContractResolver : DefaultContractResolver
{
// As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons.
// http://www.newtonsoft.com/json/help/html/ContractResolver.htm
// http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm
// "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance."
static ISupportInitializeContractResolver instance;
// Using a static constructor enables fairly lazy initialization. http://csharpindepth.com/Articles/General/Singleton.aspx
static ISupportInitializeContractResolver() { instance = new ISupportInitializeContractResolver(); }
public static ISupportInitializeContractResolver Instance { get { return instance; } }
readonly SerializationCallback onDeserializing;
readonly SerializationCallback onDeserialized;
protected ISupportInitializeContractResolver()
: base()
{
onDeserializing = (o, context) =>
{
var init = o as ISupportInitialize;
if (init != null)
init.BeginInit();
};
onDeserialized = (o, context) =>
{
var init = o as ISupportInitialize;
if (init != null)
init.EndInit();
};
}
protected override JsonContract CreateContract(Type objectType)
{
var contract = base.CreateContract(objectType);
if (typeof(ISupportInitialize).IsAssignableFrom(objectType))
{
contract.OnDeserializingCallbacks.Add(onDeserializing);
contract.OnDeserializedCallbacks.Add(onDeserialized);
}
return contract;
}
}
然后使用它:
var settings = new JsonSerializerSettings { ContractResolver = ISupportInitializeContractResolver.Instance };
var root = JsonConvert.DeserializeObject<ToBeSerialized>(jsonString, settings);
答案 1 :(得分:1)
我猜你不需要那个。您可以尝试使用适当的设置进行序列化:
<meta charset="UTF-8">
并像往常一样反序列化:
// intended is not needed, but it makes it easier to know whats going on.
var json = JsonConvert.SerializeObject(yourObject, Formatting.Indented, new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
PreserveReferencesHandling = PreserveReferencesHandling.Objects
});
要调用Initializ方法,可以尝试使用JSON.NET的SerializationCallbacks:
var obj = JsonConvert.DeserializeObject<ToBeSerialized>(json);