Row*_*haw 14 .net c# serialization xml-serialization
我正在尝试通过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>
Run Code Online (Sandbox Code Playgroud)
有没有办法使用默认的序列化器(以类似的方式创建类似的方法ShouldSerializeFoo)来确定每个对象的加载何时完成?
编辑:
我应该指出,暴露类似于反序列化后OnLoaded()我可以调用的方法的明显案例,让我感到"不好做".
编辑2:
为了讨论这是我当前的黑客 "方法",它适用于基本级别,但子城市节点仍然认为它需要随着更改保存(在现实世界中,对象模型要复杂得多) ,但这至少会编译,而不需要完整的源代码)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
STW*_*STW 14
嗯......它仍然不是很漂亮,但是你可以将你的反序列化逻辑重构为一个专用类,它可以在将它返回给调用者之前通知反序列化对象它来自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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
接受的解决方案对我来说不太有效。重写的Deserialize()方法从未被调用。我相信这是因为该方法不是公共的,因此由一个(或多个)公共方法调用Deserialize(),但不是全部。
下面是一个通过方法隐藏工作并利用现有IDeserializationCallback接口的实现,因此任何使用非 xml 方法的反序列化仍然可以触发OnDeserialization()该接口的方法。它还使用反射来遍历子属性以查看它们是否也IDeserializationCallback相应地实现和调用它们。
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Xml;
using System.Xml.Serialization;
namespace Xml.Serialization
{
class XmlCallbackSerializer : XmlSerializer
{
public XmlCallbackSerializer(Type type) : base(type)
{
}
public XmlCallbackSerializer(XmlTypeMapping xmlTypeMapping) : base(xmlTypeMapping)
{
}
public XmlCallbackSerializer(Type type, string defaultNamespace) : base(type, defaultNamespace)
{
}
public XmlCallbackSerializer(Type type, Type[] extraTypes) : base(type, extraTypes)
{
}
public XmlCallbackSerializer(Type type, XmlAttributeOverrides overrides) : base(type, overrides)
{
}
public XmlCallbackSerializer(Type type, XmlRootAttribute root) : base(type, root)
{
}
public XmlCallbackSerializer(Type type, XmlAttributeOverrides overrides, Type[] extraTypes,
XmlRootAttribute root, string defaultNamespace) : base(type, overrides, extraTypes, root, defaultNamespace)
{
}
public XmlCallbackSerializer(Type type, XmlAttributeOverrides overrides, Type[] extraTypes,
XmlRootAttribute root, string defaultNamespace, string location)
: base(type, overrides, extraTypes, root, defaultNamespace, location)
{
}
public new object Deserialize(Stream stream)
{
var result = base.Deserialize(stream);
CheckForDeserializationCallbacks(result);
return result;
}
public new object Deserialize(TextReader textReader)
{
var result = base.Deserialize(textReader);
CheckForDeserializationCallbacks(result);
return result;
}
public new object Deserialize(XmlReader xmlReader)
{
var result = base.Deserialize(xmlReader);
CheckForDeserializationCallbacks(result);
return result;
}
public new object Deserialize(XmlSerializationReader reader)
{
var result = base.Deserialize(reader);
CheckForDeserializationCallbacks(result);
return result;
}
public new object Deserialize(XmlReader xmlReader, string encodingStyle)
{
var result = base.Deserialize(xmlReader, encodingStyle);
CheckForDeserializationCallbacks(result);
return result;
}
public new object Deserialize(XmlReader xmlReader, XmlDeserializationEvents events)
{
var result = base.Deserialize(xmlReader, events);
CheckForDeserializationCallbacks(result);
return result;
}
public new object Deserialize(XmlReader xmlReader, string encodingStyle, XmlDeserializationEvents events)
{
var result = base.Deserialize(xmlReader, encodingStyle, events);
CheckForDeserializationCallbacks(result);
return result;
}
private void CheckForDeserializationCallbacks(object deserializedObject)
{
var deserializationCallback = deserializedObject as IDeserializationCallback;
if (deserializationCallback != null)
{
deserializationCallback.OnDeserialization(this);
}
var properties = deserializedObject.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var propertyInfo in properties)
{
if (propertyInfo.PropertyType.GetInterface(typeof(IEnumerable<>).FullName) != null)
{
var collection = propertyInfo.GetValue(deserializedObject) as IEnumerable;
if (collection != null)
{
foreach (var item in collection)
{
CheckForDeserializationCallbacks(item);
}
}
}
else
{
CheckForDeserializationCallbacks(propertyInfo.GetValue(deserializedObject));
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11845 次 |
| 最近记录: |