处理集合的XML序列化的通用解决方案接口

时间:2018-06-09 19:17:25

标签: c# xml serialization collections interface

我在FIFTY-FITY的基础上发布此内容。

50%可能我错过了一些明显的东西,其他人会告诉我为什么我是一个doofus - 在这种情况下,这可以更简单地完成吗?告诉我,如果你愿意,我错了 - 但请不要咬得太厉害!

50%我的解决方案实际上很有用,而其他人可能会很感激。

无论哪种方式,我希望学到一些东西。

我正在使用XML序列化来完成一个非常重要的项目,我有一个分析生产线。生产线上有很多步骤,所以我写了一些非常抽象的基础机器作为它们的基础。这已经做了很多工作! 60k行代码。 1,000种类型。

我现在要做的是将生产线的任何部分序列化为XML,而无需为生产线中的每个组件编写自定义序列化代码。我想要一个基类中的单一方法。到目前为止,没有什么不寻常的。

但是小报是C#(好吧,.NET)

  1. 无法序列化词典
  2. 无法序列化接口
  3. 在XML序列化中提供有限的调试,日志记录和可检查性。
  4. 所以我在我的基类中编写了以下函数所有继承。

        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;
        }
    

    所以

    1. 这种方法听起来不错吗?
    2. 可以改进还是缩写?
    3. 其他人是否已经发布了更好的解决方案?

0 个答案:

没有答案