我在FIFTY-FITY的基础上发布此内容。
50%可能我错过了一些明显的东西,其他人会告诉我为什么我是一个doofus - 在这种情况下,这可以更简单地完成吗?告诉我,如果你愿意,我错了 - 但请不要咬得太厉害!
50%我的解决方案实际上很有用,而其他人可能会很感激。
无论哪种方式,我希望学到一些东西。
我正在使用XML序列化来完成一个非常重要的项目,我有一个分析生产线。生产线上有很多步骤,所以我写了一些非常抽象的基础机器作为它们的基础。这已经做了很多工作! 60k行代码。 1,000种类型。
我现在要做的是将生产线的任何部分序列化为XML,而无需为生产线中的每个组件编写自定义序列化代码。我想要一个基类中的单一方法。到目前为止,没有什么不寻常的。
但是小报是C#(好吧,.NET)
所以我在我的基类中编写了以下函数所有继承。
public void WriteXml(XmlWriter writer)
{
Console.WriteLine("############### WRITING XML FOR " + GetType() + " " + this.Name);
foreach (FieldInfo fieldInfo in this.GetFieldInfos(this))
{
try
{
string fieldName = fieldInfo.Name;
var fieldValue = fieldInfo.GetValue(this);
if (!IsBackFieldName(fieldName))
{
Console.WriteLine("Serializing\t" + fieldInfo.FieldType + "\t\t" + fieldName + "\t" + fieldValue);
if (fieldInfo.FieldType.IsDictionary())
{
// TODO intercept any Dictionary type and convert to SerializableDictionary
;
}
writer.WriteStartElement(fieldName);
if (fieldInfo.FieldType.IsXmlSerializable())
{
XmlSerializer xmlSerializer;
if (fieldInfo.FieldType.IsInterface)
{
// look through the interface to the underlying type, which will have a parameterless constructor for serialization
IData castedValue = fieldValue as IData;
Type lookThroughClass = castedValue.SerializationType;
xmlSerializer = new XmlSerializer(lookThroughClass);
}
else
xmlSerializer = new XmlSerializer(fieldInfo.FieldType);
// serialization here can be built-in or overriden if IXmlSerializable is implemented
xmlSerializer.Serialize(writer, fieldValue);
}
else
{
writer.WriteComment("Not serializable " + fieldInfo.FieldType);
}
writer.WriteEndElement();
}
else
{
// skip backing field
Console.WriteLine("SKIPPING\t" + fieldInfo.FieldType + "\t\t" + fieldName + "\t" + fieldValue);
;
}
}
catch (Exception e)
{
Console.WriteLine("Error writing XML: " + e.Message);
}
}
foreach (PropertyInfo propertyInfo in GetPropertyInfos(this))
{
try
{
string propertyName = propertyInfo.Name;
var propertyValue = propertyInfo.GetValue(this);
if (!IsBackFieldName(propertyName))
{
Console.WriteLine("Serializing\t" + propertyInfo.PropertyType + "\t\t" + propertyName + "\t" + propertyValue);
// TODO intercept any Dictionary type and convert to SerializableDictionary
if (propertyInfo.PropertyType.IsDictionary())
{
// TODO intercept any Dictionary type and convert to SerializableDictionary
;
}
writer.WriteStartElement(propertyName);
if (propertyInfo.PropertyType.IsXmlSerializable())
{
XmlSerializer xmlSerializer;
if (propertyInfo.PropertyType.IsInterface)
{
// look through the interface to the underlying type, which will have a parameterless constructor for serialization
IData castedValue = propertyValue as IData;
Type lookThroughClass = castedValue.SerializationType;
xmlSerializer = new XmlSerializer(lookThroughClass);
}
else
xmlSerializer = new XmlSerializer(propertyInfo.PropertyType);
// serialization here can be built-in or overriden if IXmlSerializable is implemented
xmlSerializer.Serialize(writer, propertyValue);
}
else
{
writer.WriteComment("Not serializable " + propertyInfo.PropertyType);
}
writer.WriteEndElement();
}
else
{
// skip backing field
Console.WriteLine("SKIPPING\t" + propertyInfo.PropertyType + "\t\t" + propertyName + "\t" + propertyValue);
}
}
catch (Exception e)
{
Console.WriteLine("Error writing XML: " + e.Message);
}
}
return;
}
支持基础设施是:
public interface IData
: IXmlSerializable
{
#region Members
string Name { get; }
#endregion
#region Methods
/// <summary>
/// Allows us to pass the underlying type back out through an interface.
/// We have to know the actual type for serialization, because interfaces cannot be instantiated.
/// </summary>
Type SerializationType { get; }
#endregion
}
IData由生产线的所有成员实现,该成员还继承了基类中的XML写入和读取方法。关键(可能是偷偷摸摸的)部分是每个子类必须在本地实现SerializationType
:
public Type SerializationType => GetType();
这允许在接口中显示本地范围的Type。
这些是主方法中的辅助函数:
public PropertyInfo[] GetPropertyInfos(object theObject)
{
// https://stackoverflow.com/questions/6536163/how-to-list-all-variables-of-class
BindingFlags bindingFlags = BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.Public;
// Type theType = this.GetType();
Type theType = theObject.GetType();
PropertyInfo[] propertyInfos = theType.GetProperties(bindingFlags);
return propertyInfos;
}
public FieldInfo[] GetFieldInfos(object theObject)
{
// https://stackoverflow.com/questions/6536163/how-to-list-all-variables-of-class
BindingFlags bindingFlags = BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.Public;
// Type theType = this.GetType();
Type theType = theObject.GetType();
FieldInfo[] fieldInfos = theType.GetFields(bindingFlags);
return fieldInfos;
}
在静态的扩展类中:
public static bool IsXmlSerializable(this Type testType)
{
if (testType.IsSerializable)
return true;
// just for good measure
var interfaces = testType.GetInterfaces().ToList();
if (interfaces.Contains(typeof(IXmlSerializable)))
return true;
return false;
}
所以