Узнайте, вызывается ли установщик свойств в процессе десериализации - PullRequest
9 голосов
/ 07 ноября 2011

Есть ли способ узнать, вызывается ли свойство объекта как часть процесса десериализации (например, XmlSerializationReaderXXX).

Справочная информация. Типичный сценарий - отключение событий и сложных операций вв этом случае, до тех пор, пока инициализация не будет завершена.

Один из подходов, который я нашел, заключается в том, чтобы "интерпретировать" стек и посмотреть, вызван ли вызов XmlSerializationReaderXXX, что не так уж и элегантно для IMHO.Есть ли что-нибудь лучше?

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

- Обновление -

Как уже упоминал Сальваторе, как-то похоже на Как вы узнаете, когда вы были загружены через сериализацию XML

Ответы [ 7 ]

3 голосов
/ 07 ноября 2011

У меня есть возможное решение.

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.

2 голосов
/ 07 ноября 2011

Поскольку у вас есть довольно сложный сценарий, вы можете подумать о создании класса «ядро данных», который будет фактически сериализован / десериализован простым прямым способом. Затем ваш сложный объект создается из этого объекта, и вы запускаете все события / операции как обычно. Это сделает последовательность десериализации -> пожарных событий / операций более понятной и понятной.

1 голос
/ 07 ноября 2011

Для более точного управления процессом десериализации вы можете реализовать IXmlSerializable интерфейс для SomeClass - в ReadXML вы можете, например, в каком-то поле установить флаг, что вы находитесь в десериализации.... затем этот флаг можно проверить в соответствующих методах ... и по завершении его необходимо сбросить.

Другой вариант (хотя и не для XML IIRC) - реализовать вышеуказанное с помощью * 1009.* и OnDeserializedAttribute.

1 голос
/ 07 ноября 2011

Для решения XML Serialization можно реализовать IXmlSerializable и внедрить такую ​​логику в метод ReadXml()/WriteXml()

1 голос
/ 07 ноября 2011

Существует пара атрибутов OnDeserializingAttribute / OnDeserializedAttribute. Вы можете установить флаг isDeserializing во время десериализации объекта. Я не знаю, хорошо ли они играют с сериализацией XML.

0 голосов
/ 07 ноября 2011

Установите точку останова для свойства и запустите в режиме отладки.Он сломается в точке доступа для получателя / установщика, для которого вы установили точку останова.

0 голосов
/ 07 ноября 2011

Сначала я неправильно понял вопрос, но вы хотите спросить изнутри сеттера, вызывали ли вы во время десериализации. Для этого используйте статический флаг:

    [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
    }

Обратите внимание, что тот же подход может работать, даже если вы десериализуете класс, содержащий член вашего класса ...

...