(De) Сериализация "объекта" - PullRequest
       12

(De) Сериализация "объекта"

0 голосов
/ 29 сентября 2011

Я должен XML (де) сериализовать следующий класс:

enter image description here

это дает следующий вывод:

<ArrayOfPropertyFilter xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                       xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <PropertyFilter>
    <AndOr>And</AndOr>
    <LeftBracket>None</LeftBracket>
    <Property>17</Property>
    <Operator>Equal</Operator>
    <Value xsi:type="xsd:string">lll</Value>
    <RightBracket>None</RightBracket>
  </PropertyFilter>
</ArrayOfPropertyFilter>

и после десериализации егодает enter image description here

Как я могу "сказать" Serializer оставить значение "как есть", без какого-либо узла XML .... (в конкретном случае значение должно быть "lll", а не XMLNodeсодержащий текст «lll»)?

EDIT

Ниже приведен полный рабочий образец на C #.Вывод:

Значение = 'System.Xml.XmlNode []'

using System;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;

namespace WindowsFormsApplication13
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            PropertyFilter filter = new PropertyFilter();
            filter.AndOr = "Jora";
            filter.Value = "haha";
            filter.Property = 15;

            var xml = filter.SerializeToString();
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(xml);

            PropertyFilter cloneFilter = xmlDoc.Deserialize<PropertyFilter>();

            Console.WriteLine("Value is = '{0}'", cloneFilter.Value);
        }
    }

    public class PropertyFilter
    {
        public string AndOr { get; set; }
        public string LeftBracket { get; set; }
        public int Property { get; set; }
        public string Operator { get; set; }
        public object Value { get; set; }
        public string RightBracket { get; set; }
    }

    public static class Utils
    {
        public static string SerializeToString(this object instance)
        {
            if (instance == null)
                throw new ArgumentNullException("instance");
            StringBuilder sb = new StringBuilder();
            StringWriter sw = new StringWriter(sb);
            XmlSerializer serializer = new XmlSerializer(
                instance.GetType(), null, new Type[0], null, null);
            serializer.Serialize(sw, instance);
            return sb.ToString();
        }

        public static T Deserialize<T>(this XmlDocument xmlDoc)
        {
            XmlNodeReader reader = new XmlNodeReader(xmlDoc.DocumentElement);
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            object obj = serializer.Deserialize(reader);
            T myT = (T)obj;
            return myT;
        }

    }
}

РЕДАКТИРОВАТЬ 2

Чтобы подчеркнуть ответ Антона,второй пример (дополненный замечаниями Груо):

using System;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;

namespace WindowsFormsApplication13
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            PropertyFilter filter = new PropertyFilter();
            filter.AndOr = "Jora";
            var obj = new Hehe();
            obj.Behehe = 4526;
            filter.Value = obj;
            filter.Property = 15;

            var xml = filter.SerializeToString();
            PropertyFilter cloneFilter = xml.Deserialize<PropertyFilter>();

            Console.WriteLine("Value is = '{0}'", cloneFilter.Value);
        }
    }

    public class Hehe
    {
        public int Behehe { get; set; }
        public override string ToString()
        {
            return string.Format("behehe is '{0}'", Behehe);
        }
    }

    public class PropertyFilter
    {
        public string AndOr { get; set; }
        public string LeftBracket { get; set; }
        public int Property { get; set; }
        public string Operator { get; set; }
        //[XmlElement(typeof(Hehe))]
        public object Value { get; set; }
        public string RightBracket { get; set; }
    }

    public static class Utils
    {
        public static string SerializeToString(this object instance)
        {
            if (instance == null)
                throw new ArgumentNullException("instance");
            StringBuilder sb = new StringBuilder();

            XmlSerializer serializer = new XmlSerializer(instance.GetType(), null, new Type[0], null, null);
            using (StringWriter sw = new StringWriter(sb))
            {
                serializer.Serialize(sw, instance);
            }
            return sb.ToString();
        }

        public static T Deserialize<T>(this string xmlString)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            using (StringReader sr = new StringReader(xmlString))
            {
                return (T)serializer.Deserialize(sr);
            }
        }

    }
}

Ответы [ 3 ]

2 голосов
/ 30 сентября 2011

Хорошо, это имеет смысл, вы использовали XmlDocument для десериализации.Просто используйте String (или любой потоковый ридер, например, @Seb , на который уже указано ), и он будет работать:

public static class Utils
{
    public static string SerializeToString(this object instance)
    {
        if (instance == null)
            throw new ArgumentNullException("instance");

        StringBuilder sb = new StringBuilder();
        XmlSerializer serializer = new XmlSerializer(instance.GetType());

        using (StringWriter sw = new StringWriter(sb))
        {
            serializer.Serialize(sw, instance);
        }

        return sb.ToString();
    }

    public static T Deserialize<T>(this string xmlString)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(T));
        using (StringReader sr = new StringReader(xmlString))
        {
            return (T)serializer.Deserialize(sr);
        }
    }
}

Использование:

// serialize
var xml = filter.SerializeToString();

// deserialize
var cloneFilter = xml.Deserialize<PropertyFilter>();

[Редактировать]

Также, как примечание: никогда не забывайте располагать объекты, реализующие IDisposable.Вот почему конструкции using добавляются для любых экземпляров Stream.

[Edit2]

Как сказал Антон, в этом случае вам нужно указать дополнительные типыявно, потому что XmlSerializer не ищет все возможные типы, чтобы найти соответствующий класс.

A немного лучшее решение может быть использовать перегрузку XmlSerializer, которая принимает эти типы (чтобы вам не нужно было вручную добавлять атрибуты):

public static T Deserialize<T>(this string xmlString)
{
    Type[] typesToInclude = GetAllPossibleTypes();

    XmlSerializer serializer = new XmlSerializer(typeof(T), typesToInclude);
    using (StringReader sr = new StringReader(xmlString))
    {
        return (T)serializer.Deserialize(sr);
    }
}

Это можно сделать один раз при запуске приложения, но вам нужно предоставить соответствующую сборку (или несколько сборок), чтобы убедиться, чтопокрыты все возможные типы:

public static class Utils
{
    private static readonly Type[] _typesToInclude = GetPossibleUserTypes();

    private static Type[] GetPossibleUserTypes()
    {
        // this part should be changed to load types from the assembly
        // that contains your potential Value candidates
        Assembly assembly = Assembly.GetAssembly(typeof(PropertyFilter));

        // get public classes only
        return assembly.GetTypes().Where(t => t.IsPublic && !t.IsAbstract).ToArray();
    }

    public static string SerializeToString(this object instance)
    {
        if (instance == null)
            throw new ArgumentNullException("instance");

        var sb = new StringBuilder();
        var serializer = new XmlSerializer(instance.GetType(), _typesToInclude);

        using (StringWriter sw = new StringWriter(sb))
        {
            serializer.Serialize(sw, instance);
        }

        return sb.ToString();
    }

    public static T Deserialize<T>(this string xmlString)
    {
        var serializer = new XmlSerializer(typeof(T), _typesToInclude);
        using (StringReader sr = new StringReader(xmlString))
        {
            return (T)serializer.Deserialize(sr);
        }
    }
}
1 голос
/ 30 сентября 2011

Решение Gree будет работать, пока Value принимает значения примитивных, определенных XSD типов, таких как string и int, или пользовательских типов, упомянутых где-то в определении T (* T).типы его свойств и т. д.) Как только вам нужно десериализовать значение типа, отличного от них, вы должны объявить все возможные типы Value с XmlElementAttribute, например

[XmlElement (typeof (string))]
[XmlElement (typeof (int))]
[XmlElement (typeof (MyType), Namespace = "http://example.com/schemas/my")]
public object Value { get ; set ; }
0 голосов
/ 29 сентября 2011

Хорошо, попробуйте это, но я не уверен, чего вы пытаетесь достичь.

public class PropertyFilter
{
    public string AndOr {get; set;}
    public string LeftBracket {get; set;}
    public int Property {get; set;}
    public string Operator {get; set;}
    public object Value {get; set;}
    public string RightBracket {get; set;}
}
    public void MyMethod()
    {
        using (System.IO.StreamReader reader = new System.IO.StreamReader(@"Input.xml"))
        {
            System.Xml.Serialization.XmlSerializer serializer = new XmlSerializer(typeof(PropertyFilter[]));
            PropertyFilter[] deserialized = (PropertyFilter[])serializer.Deserialize(reader);
        }
    }

Я просто поместил ваш образец XML в Input.xml файл. Я надеюсь, что это поможет.

...