一尘不染

如何确定何时已通过XML序列化加载?

c#

我正在尝试通过XML序列化加载对象树,此刻它将加载对象,并非常愉快地创建树。我的问题围绕着以下事实:这些类支持一定程度的审核。我想做的是在每个对象加载完成后在每个对象上调用一些方法。

为了便于讨论,假设我有一个相当通用的对象树,在不同级别上具有不同的类,例如:

 <Customer name="Foo Bar Inc.">
   <Office IsHq="True">
     <Street>123 Any Street</Street>
     <Town name="Anytown">
       <State name="Anystate">
         <Country name="My Country" />
       </State>
     </Town>
   </Office>
   <Office IsHq="False">
     <Street>456 High Street</Street>
     <Town name="Anycity">
       <State name="Anystate">
         <Country name="My Country" />
       </State>
     </Town>
   </Office>
 </Customer>

有什么方法可以使用默认的序列化程序(类似于您可以创建类似方法ShouldSerializeFoo)来确定何时为每个对象完成加载?

编辑: 我应该指出,在反序列化之后暴露类似于OnLoaded()可以 调用的方法的显而易见的情况令我感到“不好做”。

Edit2: 为了便于讨论,这是我当前的 hack
“方法”,适用于基本级别,但是子City节点仍然认为它需要进行更改保存(在现实世界中,对象模型要复杂得多) ,但这至少可以编译,而无需完整的源代码)

public class Office
{
    [XmlAttribute("IsHq")]
    public bool IsHeadquarters { get; set; }

    [XmlElement]
    public string Street { get; set; }

    [XmlElement]
    public Town Town { get; set; }

    protected virtual void OnLoaded() {}

    public static OfficeCollection Search()
    {
        OfficeCollection retval = new OfficeCollection();
        string xmlString = @"
                    <Office IsHq='True'>
                        <Street>123 Any Street</Street>
                        <Town name='Anytown'>
                            <State name='Anystate'>
                                <Country name='My Country' />
                            </State>
                        </Town>
                    </Office>";

        XmlSerializer xs = new XmlSerializer(retval.GetType());
        XmlReader xr = new XmlTextReader(xmlString);
        retval = (OfficeCollection)xs.Deserialize(xr);

        foreach (Office thisOffice in retval)
        {
            thisOffice.OnLoaded();
        }
        return retval;
    }
}

阅读 206

收藏
2020-05-19

共1个答案

一尘不染

嗯…还不是很漂亮,但是您可以将反序列化逻辑重构为一个专用的类,该类可以在将其返回给调用者之前通知反序列化对象它源自XML。

更新:
我认为这应该很容易做到,而不会偏离框架设置的模式太多……您只需要确保使用CustomXmlSerializer即可。需要此通知的类仅需要实现IXmlDeserializationCallback

using System.Xml.Serialization;

namespace Custom.Xml.Serialization
{
    public interface IXmlDeserializationCallback
    {
        void OnXmlDeserialization(object sender);
    }

    public class CustomXmlSerializer : XmlSerializer
    {
        protected override object Deserialize(XmlSerializationReader reader)
        {
            var result = base.Deserialize(reader);

            var deserializedCallback = result as IXmlDeserializationCallback;
            if (deserializedCallback != null)
            {
                deserializedCallback.OnXmlDeserialization(this);
            }

            return result;
        }
    }
}
2020-05-19