Question

Je devais écrire mon propre désérialiseur, parce que XmlSerializer et DataContractSerializer ne sont pas bons pour mes besoins. Alors, voici la base de mon désérialiseur:

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

La classe BaseElement:

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

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

La seule limitation est que je ne peux pas avoir des attributs personnalisés typés parce que je ne peux pas convertir les types personnalisés à l'aide Convert.ChangeType. Toutes les idées sur la façon de résoudre ce problème?

Merci.

Était-ce utile?

La solution

Vous pouvez faire vos propres types personnalisés convertibles en mettant en œuvre l'interface IConvertible. Voici un exemple de MSDN.

Autres conseils

IConvertible ne définit pas comment une chaîne peut être utilisée pour créer une instance du type qui serait nécessaire dans ce cas. Vous pouvez créer un constructeur de conversion, mais, de façon agaçante, il ne se Nto automatiquement appelé lors d'une tentative de définir des valeurs par réflexion pour une raison quelconque. Donc, vous devez rechercher manuellement le constructeur de conversion et appeler le cas échéant. Ceci est la façon dont je le ferais:

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;
        }
     }
  }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top