使用OnDeserializing和OnDeserialized进行.NET反序列化

Ger*_*ard 17 .net c# serialization

我使用了一个可序列化的简单类.它有一个反序列化的构造函数:

protected MyClass(SerializationInfo info, StreamingContext context)
Run Code Online (Sandbox Code Playgroud)

和一个用于序列化的GetObjectData方法.它工作正常.

现在我添加了两种方法来监控反序列化:

        [OnDeserializing()]
    internal void OnDeserializingMethod(StreamingContext context)
    {
        System.Diagnostics.Trace.WriteLine("OnDeserializingMethod: " + this.GetType().ToString());
    }

    [OnDeserialized()]
    internal void OnDeserializedMethod(StreamingContext context)
    {
        System.Diagnostics.Trace.WriteLine("OnDeserializedMethod: " + this.GetType().ToString());
    }
Run Code Online (Sandbox Code Playgroud)

并且想知道这些方法的调用顺序.现在,在调用构造函数之前调用这两个方法.这怎么可能,为什么在调用(反序列化)构造函数后调用的"OnDeserialized"方法不被调用?如何在执行任何构造函数之前调用(非静态)方法?(我使用的是BinaryFormatter)

Mar*_*ell 24

现在,在调用构造函数之前调用这两个方法

不,订单是:

  • OnDeserializingMethod
  • .ctor
  • OnDeserializedMethod

如何在执行任何构造函数之前调用(非静态)方法?

因为它欺骗和谎言; 它不会使用构造函数创建对象; 不完全是.它用于FormatterServices.GetUninitializedObject分配香草空的空间.然后,如果有自定义反序列化构造函数,它将调用该对象顶部的构造函数.讨厌.像这样,基本上:

var obj = FormatterServices.GetUninitializedObject(typeof(MyClass));
var ctor = obj.GetType().GetConstructor(
    BindingFlags.Instance | BindingFlags.Public| BindingFlags.NonPublic,
    null,
    new[] { typeof(SerializationInfo), typeof(StreamingContext) },
    null);
ctor.Invoke(obj, new object[2]);
Run Code Online (Sandbox Code Playgroud)

IMO他们可能应该在ISerializable界面上做出第二种方法,但无论出于何种原因:他们没有.真的很遗憾:这会使它更诚实,并避免人们需要记住实现自定义构造函数.

示例输出:

.ctor: MyClass
> serializing
OnSerializingMethod: MyClass
GetObjectData: MyClass
OnSerializedMethod: MyClass
< serializing
> deserializing
OnDeserializingMethod: MyClass
.ctor: MyClass
OnDeserializedMethod: MyClass
< deserializing
Run Code Online (Sandbox Code Playgroud)

示例代码:

using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
[Serializable]
class MyClass : ISerializable
{
    public MyClass() { Trace(); }
    protected MyClass(SerializationInfo info, StreamingContext context) { Trace(); }
    public void GetObjectData(SerializationInfo info, StreamingContext context) { Trace(); }
    void Trace([CallerMemberName] string caller = null)
    {
        System.Console.WriteLine("{0}: {1}", caller, GetType().Name);
    }
    [OnDeserializing()]
    internal void OnDeserializingMethod(StreamingContext context) { Trace(); }

    [OnDeserialized()]
    internal void OnDeserializedMethod(StreamingContext context) { Trace(); }

    [OnSerializing()]
    internal void OnSerializingMethod(StreamingContext context) { Trace(); }

    [OnSerialized()]
    internal void OnSerializedMethod(StreamingContext context) { Trace(); }

    static void Main()
    {
        using (var ms = new MemoryStream())
        {
            var orig = new MyClass();
            var ser = new BinaryFormatter();
            System.Console.WriteLine("> serializing");
            ser.Serialize(ms, orig);
            System.Console.WriteLine("< serializing");
            ms.Position = 0;
            System.Console.WriteLine("> deserializing");
            ser.Deserialize(ms);
            System.Console.WriteLine("< deserializing");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)