首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 兩種高效方式將 XML 解析為物件集合:XmlReader 與 LINQ to XML

     編輯:關於C#

前言:從序列化轉向反序列化

上篇示範物件轉 XML,本文著重於 XML 解析為強型別集合,並引入 ClassAttribute/PropertyAttribute 支援類別與屬性別名對應,同時以字典快取屬性資訊優化反射效能。

架構設計:三大輔助類別

類別圖設計
圖 1:解析器核心類別關係
  • AttributeUtility:取得類別/屬性的 XML 對應名稱 (優先 Attribute 別名,否則用原名)。
  • ReflectionUtility:建立 Dictionary<string, PropertyInfo>,Key 為 XML 屬性名,Value 為屬性反射物件,一次反射多次複用。
  • XmlParser:核心解析器,提供兩種解析策略。

核心輔助類別實作

AttributeUtility:名稱解析

public static string GetClassName<T>() where T : new() => GetClassName(typeof(T));
public static string GetClassName(Type type)
{
    if (type == null) return string.Empty;
    string name = type.Name;
    var attrs = type.GetCustomAttributes(typeof(ClassAttribute), false) as ClassAttribute[];
    if (attrs != null && attrs.Length > 0 && !string.IsNullOrWhiteSpace(attrs[0].Name))
        name = attrs[0].Name;
    return name;
}

public static string GetPropertyName(PropertyInfo prop)
{
    if (prop == null) return string.Empty;
    string name = prop.Name;
    var attrs = prop.GetCustomAttributes(typeof(PropertyAttribute), false) as PropertyAttribute[];
    if (attrs != null && attrs.Length > 0 && !string.IsNullOrWhiteSpace(attrs[0].Name))
        name = attrs[0].Name;
    return name;
}

ReflectionUtility:屬性字典快取

public static Dictionary<string, PropertyInfo> GetPropertyMapperDictionary<T>() where T : new()
    => GetPropertyMapperDictionary(typeof(T));

public static Dictionary<string, PropertyInfo> GetPropertyMapperDictionary(Type type)
{
    if (type == null) return null;
    var dict = new Dictionary<string, PropertyInfo>();
    foreach (PropertyInfo prop in type.GetProperties())
        dict.Add(AttributeUtility.GetPropertyName(prop), prop);
    return dict;
}

XmlParser:雙模式解析

模式一:XmlReader 循序流式解析 (低記憶體、高效能)

public static IList<T> Parse<T>(XmlReader reader) where T : new()
{
    try { return ParseXmlReader<T>(reader); } catch { return new List<T>(); }
}

private static IList<T> ParseXmlReader<T>(XmlReader reader) where T : new()
{
    var propDict = ReflectionUtility.GetPropertyMapperDictionary<T>();
    string className = AttributeUtility.GetClassName<T>();
    var entities = new List<T>();
    T entity = new T();
    string lastElementName = null;

    while (reader.Read())
    {
        switch (reader.NodeType)
        {
            case XmlNodeType.Element:
                if (string.Equals(reader.Name, className))
                {
                    entity = new T();
                    entities.Add(entity);
                }
                lastElementName = reader.Name;
                break;
            case XmlNodeType.Text:
                SetPropertyValue(propDict, entity, lastElementName, reader.Value);
                break;
        }
    }
    return entities;
}

模式二:LINQ to XML 節點集合解析 (程式碼簡潔、易維護)

public static IList<T> Parse<T>(IEnumerable<XElement> elements) where T : new()
{
    if (elements == null || !elements.Any()) return new List<T>();
    try
    {
        var propDict = ReflectionUtility.GetPropertyMapperDictionary<T>();
        var entities = new List<T>();
        foreach (XElement el in elements)
        {
            T entity = new T();
            entities.Add(entity);
            foreach (XElement child in el.Elements())
                SetPropertyValue(propDict, entity, child.Name.LocalName, child.Value);
        }
        return entities;
    }
    catch { return new List<T>(); }
}

統一屬性賦值邏輯


private static void SetPropertyValue<T>(Dictionary<string, PropertyInfo> dict, T entity, string xmlName, string value) where T : new()
{
    if (string.IsNullOrWhiteSpace(xmlName) || !dict.ContainsKey(xmlName)) return;
    PropertyInfo prop = dict[xmlName];
    if (prop != null && prop.CanWrite)
    {
        object val = new FuncDictionary().DynamicInvoke(prop.PropertyType, value);
        prop.SetValue(entity, val, null);
    }
}

效能優化關鍵

反射資訊快取:無論解析多少實體,ReflectionUtility.GetPropertyMapperDictionary<T>() 僅呼叫一次,後續皆以字典查找 PropertyInfo,大幅降低反射開銷。對於物件數量不大的情境,效能差異可忽略;大量資料時效果顯著。

適用 XML 格式

<MapperInfoItem>
  <DefaultName>MapperInfoItemIndex0</DefaultName>
  <CreatedTime>2012/1/6 19:24:34</CreatedTime>
  <IsActive>True</IsActive>
  ...
</MapperInfoItem>

以上兩種解析器均能正確處理此類「子元素對應屬性」的 XML 結構。

作者:JasenKin | 出處:https://www.cnblogs.com/jasenkin/

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved