找出是否在DeSerialization过程中调用属性设置器

时间:2011-11-07 14:44:14

标签: c# c#-4.0 deserialization

有没有办法找出对象属性是否作为DeSerialization过程的一部分被调用(例如XmlSerializationReaderXXX)。

背景:典型的情况是在这种情况下禁用事件和复杂操作,直到初始化完成。

我发现的一种方法是“解释”堆栈并查看调用是否由XmlSerializationReaderXXX触发,这不是那么优雅的恕我直言。还有什么更好的吗?

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

- 更新 -

正如Salvatore所提到的,某种程度上类似于How do you find out when you've been loaded via XML Serialization?

7 个答案:

答案 0 :(得分:3)

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

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。它支持OnDeserializationCallback机制。

答案 1 :(得分:2)

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

答案 2 :(得分:1)

有一个OnDeserializingAttribute / OnDeserializedAttribute属性对。您可以在反序列化对象时设置isDeserializing标志。不过,我不知道他们是否能很好地使用XML序列化。

答案 3 :(得分:1)

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

答案 4 :(得分:1)

为了更好地控制反序列化过程,您可以为SomeClass实现IXmlSerializable interface - 在ReadXML中,您可以为某个字段设置一个标记,您正在进行反序列化。然后可以在相应的方法中检查此标志......并且在完成时需要重置它。

另一个选择(虽然不适用于XML IIRC)是通过OnDeserializingAttributeOnDeserializedAttribute来实现上述内容。

答案 5 :(得分:0)

我最初误解了这个问题,但是你想在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
    }

请注意,即使您反序列化包含类成员的类,相同的方法也可以工作...

答案 6 :(得分:0)

在属性上设置断点,并以调试模式运行。它将在您设置断点的getter / setter的访问点处中断。