0

XmlSerializer と DataContractSerializer は私のニーズに合わないため、独自のデシリアライザーを作成する必要がありました。したがって、これが私のデシリアライザーのベースです。

    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 を使用してカスタム型に変換できないため、カスタム型の属性を持つことができないことです。これを解決する方法についてのアイデアはありますか?

ありがとう。

4

2 に答える 2

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;
        }
     }
  }
}
于 2009-10-17T15:14:35.260 に答える
0

インターフェイスを実装することで、独自のカスタム型を変換可能にすることができIConvertibleます。MSDNの例を次に示します。

于 2009-10-17T13:55:57.823 に答える