Триггерная функция при десериализации - PullRequest
8 голосов
/ 24 мая 2010

У меня есть класс с количеством полей, которые обычно вычисляются в конструкторе из других данных в классе.Они не сериализуются в XML, потому что любые изменения в остальных данных, вероятно, потребуют их пересчета.

Есть ли способ настроить вызов функции для запуска при десериализации?

Ответы [ 4 ]

5 голосов
/ 24 мая 2010

То, что вы описываете, это [OnDeserialized]

XmlSerializer не поддерживает методы обратного вызова сериализации (по крайней мере, не в MS .NET; моно может отличаться). В зависимости от ваших потребностей, вы можете попробовать DataContractSerializer, который поддерживает поддержку обратных вызовов сериализации (как и ряд других сериализаторов). В противном случае ваш лучший подход может состоять в том, чтобы просто иметь свой собственный публичный метод, который вы вызываете вручную.

Другим вариантом является ручная реализация IXmlSerializable, но это hard .

1 голос
/ 24 мая 2010

Поскольку объект, который может быть сериализован в XML, нуждается в общедоступном конструкторе без параметров, кажется, что у вас есть дыра в дизайне класса даже до того, как вы нажмете сериализацию XML.

Лично я бы пошел с ленивым подсчетом этих полей. Сохраните флаг внутри класса независимо от того, рассчитали ли вы поля или нет, и установите для этого поля значение, означающее «устарело», когда изменяется любое из свойств, используемых в вычислении. Затем в свойствах, которые возвращают вычисленные значения, проверьте, нужно ли пересчитать перед возвратом значения.

Это будет работать независимо от сериализации XML или нет.

пример:

[XmlType("test")]
public class TestClass
{
    private int _A;
    private int? _B;

    public TestClass()
        : this(0)
    {
    }

    public TestClass(int a)
    {
        _A = a;
    }

    [XmlAttribute("a")]
    public int A
    {
        get { return _A; }
        set { _A = value; _B = null; }
    }

    [XmlIgnore]
    public int B
    {
        get { if (_B == null) Recalculate(); return _B; }
        set { _B = value; }
    }

    private void Recalculate()
    {
        _B = _A + 1;
    }
}
1 голос
/ 24 мая 2010

- Изменить:

Просто подтвердил, что, как говорит ниже комментатор, процесс сериализации xml не затрагивает метод, объявленный атрибутом OnDeserialized Какой позор.

- Предыдущий ответ:

Да, действительно, посмотрите здесь .

Особый интерес представляет атрибут OnDeserialized, обсуждаемый здесь .

Возможно, стоит отметить, что в зависимости от используемого метода сериализации (я думаю) будет вызываться ваш конструктор без аргументов. Очевидно, это произойдет до того, как будет установлено что-либо еще. Так что это, вероятно, не совсем полезно.

0 голосов
/ 24 мая 2010

Вы можете реализовать IDeserializationCallback интерфейс

...