我有一个用户定义的类,我的代码中的几乎所有对象都会扩展。我想在这个类上实现iXmlSerializeable,这样我就可以在基类级别控制对象的序列化方式。具体来说,我需要以特定方式处理对象中的DateTime字符串。是的,可能有更好的方法来欺骗应用程序从序列化的DateTime中剥离TimeZone信息。然而,我的要求迫使我忽视这张脸。我需要一种方法将其写入基本上单个函数,该函数不必在应用程序中的任何其他位置影响或更改代码,以实现此效果。
这是迄今为止的实现(仅限读者,甚至尚未启动作者):
public void ReadXml(System.Xml.XmlReader reader)
{
//loop through properties, Read property by name, converting as necessary based on property type.
Type curType = this.GetType();
PropertyInfo[] pis;
PropertyInfo prop = null;
List<PropertyInfo> piList = new List<PropertyInfo>();
//get all fields and properties (this does not need to be recursive, properties of the underlying object DO appear at this stage, unlike fields.
pis = curType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (PropertyInfo pi in pis)
piList.Add(pi);
bool isEmpty = reader.IsEmptyElement;
reader.ReadStartElement();
if (!isEmpty)
{
bool isProp = false;
while (reader.NodeType != System.Xml.XmlNodeType.EndElement)
{
if (!reader.IsEmptyElement)
{
if (piList.Select(a => a.Name).Contains(reader.Name))
isProp = true;
if (!isProp)//property not found?
{
reader.Skip();//cant do anything with it...keep going.
continue;
}
#region property set
prop = piList.Where(a => a.Name.Equals(reader.Name)).Single();
if (prop.CanWrite)
{
if (prop.PropertyType.BaseType.IsGenericType)
{//this should be one of the Rig Collections, are there any false positives?
ReadXmlCollection(prop, reader);
}
else if (prop.PropertyType.IsSubclassOf(typeof(BusinessObjectBase)))
{
//have to create a 'new' object, then call its reader to fill it in, then set the property value.
object newObj = Activator.CreateInstance(prop.PropertyType, false);
prop.PropertyType.GetMethod("ReadXml").Invoke(newObj, new object[] { reader });
prop.SetValue(this, newObj, null);
}
else
{
string elVal = reader.ReadString();
if (!String.IsNullOrEmpty(elVal))
{
if (prop.PropertyType == typeof(String))
prop.SetValue(this, elVal, null);
else if (prop.PropertyType == typeof(int) || prop.PropertyType == typeof(int?))
prop.SetValue(this, Convert.ToInt32(elVal), null);
else if (prop.PropertyType == typeof(double) || prop.PropertyType == typeof(double?))
prop.SetValue(this, Convert.ToDouble(elVal), null);
else if (prop.PropertyType == typeof(bool) || prop.PropertyType == typeof(bool?))
prop.SetValue(this, Convert.ToBoolean(elVal), null);
else if (prop.PropertyType == typeof(DateTime) || prop.PropertyType == typeof(DateTime?))
{//special handle
elVal = System.Text.RegularExpressions.Regex.Replace(elVal, @"(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2}\.?\d*)([\+|-]\d{2}:\d{2})", "$1 $2");
prop.SetValue(this, Convert.ToDateTime(elVal), null);
}
}
}
}
#endregion
}
if (prop == null)//read anyway, something weird has happened?
{
if (!reader.Read())
break;
}
else if(prop.Name.Equals(reader.Name))//only read if we are still on this node, otherwise, this has already been done.
if (!reader.Read())
break;
prop = null;
isProp = false;
}
}
reader.ReadEndElement();
}
private void ReadXmlCollection(PropertyInfo prop, System.Xml.XmlReader reader)
{
string colName = reader.Name;
object collectionIntance = Activator.CreateInstance(prop.PropertyType, false);
reader.ReadStartElement();
//now we are at the first element in the collection...what is it?
Type ColType = prop.PropertyType.BaseType.GetGenericArguments()[0];
while (reader.Name != colName && reader.NodeType != System.Xml.XmlNodeType.EndElement)
{
object colObj = Activator.CreateInstance(ColType, false);
ColType.GetMethod("ReadXml").Invoke(colObj, new object[] { reader });
prop.PropertyType.GetMethod("Add", new Type[] {ColType}).Invoke(collectionIntance, new object[] { colObj });
}
prop.SetValue(this, collectionIntance, null);
reader.ReadEndElement();
}
我认为它有效......但它也很慢。任何建议将不胜感激。
我也不介意一个大概的“好主,那是疯了,永远不会工作”......或类似的东西。请记住,这是在一个抽象基类上实现的,它在已经扩展的类型上运行。
这是我需要阅读的数据样式的一个极其截断且大规模简化的示例:
<RigX>
<isDirty>True</isDirty>
<RXJob>
<prop1>1.3</prop1>
<prop2>False<prop2>
<prop3>1984-08-10T09:30:00-06:00</prop3>
<prop4 />
<prop5>Hello World</prop5>
</RXJob>
<RXCollection>
<ColObject>
<p1>Yo</p1>
<p2>Yellow</p2>
</ColObject>
<ColObject>
<p1>No</p1>
<p2>Orange</p2>
</ColObject>
</RXCollection>
<RXNestedCollection>
<RXNestedObject>
<RXAnotherCollection>
<RXAnotherObject>
<p1>1.9</p1>
</RXAnotherObject>
</RXAnotherCollection>
<RXObject>
<prop1>nope</prop1>
<prop2>Im On A Horse!</prop2>
</RXObject>
</RXNestedObject>
</RXNestedCollection>
</RigX>
在此示例中,RigX是外部的单个对象。 IsDirty是RigX的财产。同样,RXJob,RXCollection和RXNestedCollection是RigX的属性。 RXJob是一个对象,另外两个是集合。 RXCollection是一个包含未知数量的用户定义对象的集合,每个对象都是一个只包含灵长类动物的简单对象。 RXNestedCollection包含未知数量的用户定义对象,每个对象包含其他用户定义的对象和集合。