支持使用 json.net 初始化

本文关键字:net 初始化 json 支持 | 更新日期: 2023-09-27 18:30:45

我正在使用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; }
    }

感谢任何帮助为我指明正确的方向

支持使用 json.net 初始化

如果不想

手动添加[OnDeserializing][OnDeserialized]调用BeginInit()EndInit()的回调到每个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);

我想你不需要那个。您可以尝试使用适当的设置进行序列化:

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

并像往常一样反序列化:

var obj = JsonConvert.DeserializeObject<ToBeSerialized>(json); 

若要调用 Initializ 方法,可以尝试使用 JSON。NET 的序列化回调:

public class ToBeSerialized
{
    // [...]
    // this is probably superflous if the callbacks do what you want, you can move the code there
    public SupportsInitialize SupportsInitialize { get; set; }
    [OnDeserializing]
    internal void OnDeserializingMethod(StreamingContext context)
    {
        this.SupportsInitialize.BeginInit();
    }
    [OnDeserialized]
    internal void OnDeserializedMethod(StreamingContext context)
    {
        this.SupportsInitialize.EndInit();
    }
}