2009-10-17 2 views
0

Мне пришлось написать собственный десериализатор, потому что XmlSerializer и DataContractSerializer не подходят для моих нужд. Итак, вот основа моей десериализатор:Deserializing using XElement

static BaseElement ParseXml(XElement element) 
    { 
     var e = (Element)Activator.CreateInstance(Type.GetType("Elements." + element.Name)); 

     foreach (var attr in element.Attributes()) 
     { 
      var property = e.GetType().GetProperty(attr.Name.LocalName); 
      property.SetValue(e, Convert.ChangeType(attr.Value, property.PropertyType), null); 
     } 

     foreach (var x in element.Elements()) 
      e.Elements.Add(ParseXml(x)); 

     return e; 
    } 

Класс BaseElement:

public abstract class BaseElement 
{ 
    public BaseElement() 
    { 
     Elements = new List<Element>(); 
    } 

    public IList<Element> Elements 
    { 
     get; 
     set; 
    } 
} 

Единственным ограничением является то, что я не могу быть пользовательские атрибуты набраны, потому что я не могу преобразовать пользовательские типы используя Convert.ChangeType. Любые идеи о том, как это решить?

Спасибо.

ответ

0

Вы можете создавать свои собственные типы конвертируемых объектов путем реализации интерфейса IConvertible. Here's Пример из MSDN.

0

IConvertible не определяет, как строка может использоваться для создания экземпляра типа, который необходим в этом случае. Вы можете создать конструктор преобразования, но, как это ни парадоксально, он автоматически вызывает вызов при попытке установить значения через отражение по какой-либо причине. Поэтому вам придется вручную искать конструктор преобразования и вызывать его, когда это применимо. Речь идет о том, как я это сделаю:

namespace Elements 
{ 
    class Program 
    { 
    static void Main(string[] args) 
    { 
     System.Xml.Linq.XElement sample = System.Xml.Linq.XElement.Parse(
      "<Element a=\"3\" b=\"Havarti\" modeSel=\"Complex\" />"); 

     Element c1 = Element.ParseXml(sample); 
    } 
    } 

    public class ModeSelection 
    { 
    private int mode; 

    public static explicit operator ModeSelection(string value) 
    { 
     ModeSelection result = new ModeSelection(); 
     if (String.Compare(value, "Simple", true) == 0) 
      result.mode = 1; 
     else if (String.Compare(value, "Complex", true) == 0) 
      result.mode = 2; 
     else if (!int.TryParse(value, out result.mode)) 
      throw new FormatException("Cannot convert value to type " + result.GetType().Name); 
     return result; 
    } 

    string Description 
    { 
     get 
     { 
      switch (mode) 
      { 
       case 1: 
       return "Simple"; 
       case 2: 
       return "Complex"; 
       default: 
       return "Other"; 
      } 
     } 
    } 
    } 

    public abstract class BaseElement<T> where T : BaseElement<T>, new() 
    { 
    public static T ParseXml(System.Xml.Linq.XElement element) 
    { 
     var e = (T)Activator.CreateInstance(Type.GetType("Elements." + element.Name)); 

     Type[] convParamTypes = new Type[] {typeof(string)}; 

     foreach (var attr in element.Attributes()) 
     { 
      var property = e.GetType().GetProperty(attr.Name.LocalName); 
      System.Reflection.MethodInfo conv = property.PropertyType.GetMethod(
       "op_Explicit", convParamTypes); 

      if (conv != null) 
       property.SetValue(e, conv.Invoke(null, new object[] {attr.Value}), null); 
      else 
       property.SetValue(e, Convert.ChangeType(attr.Value, property.PropertyType), null); 
     } 

     foreach (var x in element.Elements()) 
      e.Elements.Add(ParseXml(x)); 

     return e; 
    } 

    public BaseElement() 
    { 
     Elements = new List<T>(); 
    } 

    public IList<T> Elements 
    { 
     get; 
     set; 
    } 
    } 

    public class Element : BaseElement<Element> 
    { 
    int _a; 
    string _b; 
    ModeSelection _modeSel; 

    public int a 
    { 
     get 
     { 
      return _a; 
     } 
     set 
     { 
      _a = value; 
     } 
    } 

    public string b 
    { 
     get 
     { 
      return _b; 
     } 
     set 
     { 
      _b = value; 
     } 
    } 

    public ModeSelection modeSel 
    { 
     get 
     { 
      return _modeSel; 
     } 
     set 
     { 
      _modeSel = value; 
     } 
    } 
    } 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^