查明反序列化过程中是否调用了属性设置器

本文关键字:属性 设置 调用 是否 反序列化 过程中 | 更新日期: 2023-09-27 18:13:47

是否有一种方法可以找出对象属性是否作为反序列化过程的一部分被调用(例如由XmlSerializationReaderXXX)。

后台:典型的场景是禁用事件和复杂的操作,直到初始化完成。

我发现的一种方法是"解释"堆栈并查找调用是否由XmlSerializationReaderXXX触发,这在我看来不是那么优雅。有更好的吗?

public SomeClass SomeProperty
    {
        get { ..... }
        set
        {
            this._somePropertyValue = value;
            this.DoSomeMoreStuff(); // Do not do this during DeSerialization
        }
    }

—Update—

正如Salvatore所提到的,在某种程度上类似于您如何发现您已通过XML序列化加载?

查明反序列化过程中是否调用了属性设置器

我有一个可能的解决方案。

public class xxx
{
    private int myValue;
    [XmlElement("MyProperty")]
    public int MyPropertyForSerialization
    {
        get { return this.myValue; }
        set
        {
            Console.WriteLine("DESERIALIZED");
            this.myValue = value;
        }
    }
    [XmlIgnore]
    public int MyProperty
    {
        get { return this.myValue; }
        set
        {
            Console.WriteLine("NORMAL");
            this.myValue = value;
        }
    }
}
class Program
{
    static void Main(string[] args)
    {
        xxx instance = new xxx();
        instance.MyProperty = 100; // This should print "NORMAL"
        // We serialize
        var serializer = new XmlSerializer(typeof(xxx));
        var memoryStream = new MemoryStream();
        serializer.Serialize(memoryStream, instance);
        // Let's print our XML so we understand what's going on.
        memoryStream.Position = 0;
        var reader = new StreamReader(memoryStream);
        Console.WriteLine(reader.ReadToEnd());
        // Now we deserialize
        memoryStream.Position = 0;
        var deserialized = serializer.Deserialize(memoryStream) as xxx; // This should print DESERIALIZED
        Console.ReadLine();
    }
}

技巧是使用XmlIgnore,它将强制xml序列化器忽略我们的属性,然后我们使用XmlElement用我们想要的属性名称重命名该属性以进行序列化。

这种技术的问题是,您必须为序列化公开一个公共属性,并且在某种程度上是不好的,因为它实际上可以被每个人调用。不幸的是,如果成员是私有的,它将不起作用。

它工作,不是完全干净,但线程安全,不依赖任何标志。

另一种可能性是使用类似于Memento模式的东西。使用相同的技巧,您可以添加一个属性,例如Memento,它返回另一个对象,其中包含只适合序列化的属性,它可以使事情变得更简洁。

你是否考虑过不改变方法而使用DataContractSerializer?它更强大,可以生成纯XML。它支持ondeseralizationcallback机制

由于您有一个相当复杂的场景,您可能想要考虑创建一个"数据核心"类,它将实际序列化/反序列化使用简单的直接方式。然后从该对象构造复杂对象,并像往常一样触发所有事件/操作。它将使反序列化-> fire事件/操作的序列更明确,更容易理解。

存在一个OnDeserializingAttribute/OnDeserializedAttribute属性对。可以在对象反序列化时设置isDeserializing标志。不过我不知道它们是否能很好地处理XML序列化。

对于XML序列化解决方案可以实现IXmlSerializable并将这种逻辑嵌入到ReadXml()/WriteXml()方法中

为了更好地控制反序列化过程,您可以为SomeClass实现IXmlSerializable接口-在ReadXML中,您可以例如有一些字段设置反序列化标志…然后可以在各自的方法中检查该标志…完成后需要重置

另一个选项(虽然不适合XML IIRC)是通过OnDeserializingAttributeOnDeserializedAttribute实现上述功能。

一开始我误解了这个问题,但是您想从setter内部询问您是否在反序列化期间被调用。为此,使用静态标志:

    [serializable]
    class SomeClass
    {
       public static IsSerializing = false;
       SomeProperty
       {
            set
            {
                 if(IsSerializing) DoYouStuff();
            }
       }
    }

,然后在序列化之前设置标志:

    try
    {
      SomeClass.IsSerializing = true;
      deserializedClass = (SomeClass)serializer.Deserialize(reader);
    }
    finaly
    {
      SomeClass.IsSerializing = false;  //make absolutely sure you set it back to false
    }

注意,同样的方法可以工作,即使你反序列化一个类,其中包含你的类的成员…

在属性上设置断点,并在调试模式下运行。