Pregunta

Tuve que escribir mi propio deserializador, porque XMLSerializer y DataContractserializer no son buenos para mis necesidades. Entonces, aquí está la base de mi deserializador:

    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 clase de base:

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

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

La única limitación es que no puedo tener atributos tipificados personalizados porque no puedo convertir a tipos personalizados usando convert.ChangeType. ¿Alguna idea sobre cómo resolver esto?

Gracias.

¿Fue útil?

Solución

Puede hacer que sus propios tipos personalizados se conviertan implementando el IConvertible interfaz. Aquí es Un ejemplo de MSDN.

Otros consejos

Iconvertible no define cómo se puede usar una cadena para crear una instancia del tipo como se necesitaría en este caso. Puede crear un constructor de conversión, pero, molesto, no se llama automáticamente al intentar establecer valores a través de la reflexión por alguna razón. Por lo tanto, tendrá que buscar manualmente el constructor de conversión y llamarlo cuando corresponda. Esto se trata de cómo lo haría:

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;
        }
     }
  }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top