【问题标题】:Overriding XML deserialization to use base deserialization and adding functionality覆盖 XML 反序列化以使用基本反序列化并添加功能
【发布时间】:2012-04-15 22:21:23
【问题描述】:

我有一个应该被序列化和反序列化的类。

但是每次反序列化后我都需要调用一个同步引用的方法。

无论如何我可以实现反序列化并使用传统的反序列化,但在常规反序列化之后添加对我的方法的调用?

【问题讨论】:

  • 你能澄清一下“我需要调用同步引用的方法”的确切含义吗?请解释为什么这也是需要的。
  • 例如类包括:成员 A、MemberB 和具有 xmlIgnore 且应包含成员 A 和 B 的成员列表 常规反序列化将为列表和成员创建不同的实例 我需要列表引用被反序列化的成员。问题如何创建后反序列化方法?或实施并调用常规反序列化
  • 你能举个例子吗?目前尚不清楚您要完成什么。您想在每次反序列化后在对象上使用 XmlIgnore 填充其他成员字段?

标签: c# xml serialization xml-serialization xmlserializer


【解决方案1】:
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;
        }
    }
}

从 IXmlDeserializationCallback 继承您的类并在 OnXmlDeserialization 方法中实现您的同步逻辑。

感谢How do you find out when you've been loaded via XML Serialization?

更新:

好吧,据我了解topicstarter,他不想在每次XML反序列化之后“手动”调用一些逻辑。所以不要这样做:

public class MyEntity
{
     public string SomeData { get; set; }

     public void FixReferences()
     {
          // call after deserialization
          // ...
     }
}

foreach (var xmlData in xmlArray)
{
    var xmlSer = new XmlSerializer(typeof(MyEntity));
    using (var memStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlData)))
    {
       var entity = (MyEntity)xmlSer.Deserialize(memStream);
       entity.FixReferences();

       // do something else with the entity
       // ...  
    }
}

他只想做反序列化,而不用担心额外的调用。在这种情况下,建议的解决方案是最干净/最简单的 - 您只需从 IXmlDeserializationCallback 接口继承您的实体类,并将 XmlSerializer 替换为 CustomXmlSerializer:

 public class MyEntity: IXmlDeserializationCallback
    {
         public string SomeData { get; set; }

         private void FixReferences()
         {
              // call after deserialization
              // ...
         }

         public void OnXmlDeserialization(object sender)
         {
             FixReferences();
         } 
    }

    foreach (var xmlData in xmlArray)
    {
        var xmlSer = new CustomXmlSerializer(typeof(MyEntity));
        using (var memStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlData)))
        {
           var entity = (MyEntity)xmlSer.Deserialize(memStream);
           // entity.FixReferences(); - will be called automatically

           // do something else with the entity
           // ...  
        }
    }

【讨论】:

  • 知道为什么在 .NET 4.5 中不调用重写的方法吗?
【解决方案2】:

我有一个很好的解决方案 4 u

编写这个静态类

public delegate void OnDeserializedEventArgs(object itemDeserialized, string xmlSource);
public delegate void OnDeserializedFailedEventArgs(string xmlSource);
public static class SerializationServices
{
    public static event OnDeserializedEventArgs OnDeserializedEvent;
    public static event OnDeserializedFailedEventArgs OnDeserializedFailedEvent;

    public static T Deserialize<T>(this string item) where T : class
    {
        XmlSerializer ser = new XmlSerializer(item.GetType());
        StringReader sr = new StringReader(item);
        var obj = ser.Deserialize(sr);

        if (obj is T)
        {
            if (OnDeserializedEvent != null)
                OnDeserializedEvent(obj, item);

            return obj as T;
        }

        if (OnDeserializedFailedEvent != null)
            OnDeserializedFailedEvent(item);

        //callback - invalid event
        return null;
    }
}

然后在这段代码中使用它

public class MyDesrializedClass
{
    //put some properties here...
}
class Program
{
    static void Main(string[] args)
    {
        SerializationServices.OnDeserializedEvent += SerializationServices_OnDeserializedEvent;
        SerializationServices.OnDeserializedFailedEvent += SerializationServices_OnDeserializedFailedEvent;

        string someXml = string.Empty; //replace this with something...
        MyDesrializedClass deserializedClass = someXml.Deserialize<MyDesrializedClass>();
    }

    private static void SerializationServices_OnDeserializedFailedEvent(string xmlSource)
    {
        //will get here before 'deserializedClass' will get it's results
    }

    private static void SerializationServices_OnDeserializedEvent(object itemDeserialized, string xmlSource)
    {
        //will get here before 'deserializedClass' will get it's results
    }
}

如果您将这些代码粘贴到不同的命名空间中,请不要忘记添加“使用 ...”,否则您将不会在程序上下文中看到反序列化方法

扎希

【讨论】:

  • 请注意,我的解决方案不需要您继承任何基类,也不需要您初始化新实例
【解决方案3】:

您使用 XmlSerializer 的选项有限。

  • 反序列化整个对象图,然后应用您需要的任何修复。
  • 在对象的属性设置器中进行一些处理。
  • 在您的类型上实现IXmlSerializable,以便您可以显式控制序列化/反序列化。这不是一个简单的选择。

如果您可以改用DataContractSerializer,它有其优点(和缺点),那么您可以使用OnDeserializedAttribute。例如

[DataContract]
public class MyClass
{
    [DataMember]
    public string AMember{get;set;}

    [OnDeserialized]
    public void OnDeserialized(StreamingContext context)
    {
        // called after deserializing instance of MyClass
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-24
    • 2011-05-12
    • 1970-01-01
    • 2012-03-04
    • 2011-03-03
    相关资源
    最近更新 更多