XML Сериализируют универсальный список сериализуемых объектов

почему не что-то вроде этого:

 Dim ar As New ArrayList
    Dim numToGet As Integer = 5
    'hard code just to test
    ar.Add("12")
    ar.Add("11")
    ar.Add("10")
    ar.Add("15")
    ar.Add("16")
    ar.Add("17")

    Dim randomListOfProductIds As New ArrayList

    Dim toAdd As String = ""
    For i = 0 To numToGet - 1
        toAdd = ar(CInt((ar.Count - 1) * Rnd()))

        randomListOfProductIds.Add(toAdd)
        'remove from id list
        ar.Remove(toAdd)

    Next
'sorry i'm lazy and have to write vb at work :( and didn't feel like converting to c#
71
задан Dima 18 March 2013 в 19:13
поделиться

6 ответов

Вы не можете сериализовать коллекцию объектов без указания ожидаемых типов. Вы должны передать список ожидаемых типов в конструктор XmlSerializer (параметр extraTypes ):

List<object> list = new List<object>();
list.Add(new Foo());
list.Add(new Bar());

XmlSerializer xs = new XmlSerializer(typeof(object), new Type[] {typeof(Foo), typeof(Bar)});
using (StreamWriter streamWriter = System.IO.File.CreateText(fileName))
{
    xs.Serialize(streamWriter, list);
}

Если все объекты вашего списка наследуются от одного и того же класса, вы также можете используйте атрибут XmlInclude , чтобы указать ожидаемые типы:

[XmlInclude(typeof(Foo)), XmlInclude(typeof(Bar))]
public class MyBaseClass
{
}
5
ответ дан 24 November 2019 в 13:04
поделиться

Я думаю, что лучше всего использовать методы с общими аргументами, например:

public static void SerializeToXml<T>(T obj, string fileName)
{
    using (var fileStream = new FileStream(fileName, FileMode.Create))
    { 
        var ser = new XmlSerializer(typeof(T)); 
        ser.Serialize(fileStream, obj);
    }
}

public static T DeserializeFromXml<T>(string xml)
{
    T result;
    var ser = new XmlSerializer(typeof(T));
    using (var tr = new StringReader(xml))
    {
        result = (T)ser.Deserialize(tr);
    }
    return result;
}
4
ответ дан 24 November 2019 в 13:04
поделиться

Я думаю, что подход Дреаса приемлем. Однако альтернативой этому является наличие некоторых статических вспомогательных методов и реализация IXmlSerializable для каждого из ваших методов, например, метод расширения XmlWriter и метод XmlReader, чтобы читать его обратно.

public static void SaveXmlSerialiableElement<T>(this XmlWriter writer, String elementName, T element) where T : IXmlSerializable
{
   writer.WriteStartElement(elementName);
   writer.WriteAttributeString("TYPE", element.GetType().AssemblyQualifiedName);
   element.WriteXml(writer);
   writer.WriteEndElement();
}

public static T ReadXmlSerializableElement<T>(this XmlReader reader, String elementName) where T : IXmlSerializable
{
   reader.ReadToElement(elementName);

   Type elementType = Type.GetType(reader.GetAttribute("TYPE"));
   T element = (T)Activator.CreateInstance(elementType);
   element.ReadXml(reader);
   return element;
}

Если вы все же идете по маршруту использования класса XmlSerializer напрямую по возможности заранее создавайте сборки сериализации, так как вы можете значительно снизить производительность при регулярном построении новых XmlSerializers.

Для коллекции вам понадобится что-то вроде этого:

public static void SaveXmlSerialiazbleCollection<T>(this XmlWriter writer, String collectionName, String elementName, IEnumerable<T> items) where T : IXmlSerializable
{
   writer.WriteStartElement(collectionName);
   foreach (T item in items)
   {
      writer.WriteStartElement(elementName);
      writer.WriteAttributeString("TYPE", item.GetType().AssemblyQualifiedName);
      item.WriteXml(writer);
      writer.WriteEndElement();
   }
   writer.WriteEndElement();
}
3
ответ дан 24 November 2019 в 13:04
поделиться

См. Введение в сериализацию XML :

Элементы, которые можно сериализовать

Следующие элементы можно сериализовать с помощью XmlSerializer class:

  • Общедоступные свойства чтения / записи и поля общедоступных классов
  • Классы, реализующие ICollection или IEnumerable
  • XmlElement объекты
  • объекты XmlNode
  • DataSet объекты

В частности, ISerializable или атрибут [Serializable] не имеют значения.


Теперь, когда вы сообщили нам, в чем заключается ваша проблема. («это не работает» не является формулировкой проблемы), вы можете получить ответы на вашу реальную проблему вместо предположений.

Когда вы сериализуете коллекцию типа, но на самом деле сериализуете коллекцию экземпляров производные типы, вам необходимо сообщить сериализатору, какие типы вы на самом деле будете сериализовать. Это также верно для коллекций объекта .

Вам необходимо использовать XmlSerializer (Type,

22
ответ дан 24 November 2019 в 13:04
поделиться

Если требования вывода XML можно изменить, вы всегда можете использовать двоичную сериализацию, которая лучше подходит для работы с разнородными списками объектов. Вот пример:

private void SerializeList(List<Object> Targets, string TargetPath)
{
    IFormatter Formatter = new BinaryFormatter();

    using (FileStream OutputStream = System.IO.File.Create(TargetPath))
    {
        try
        {
            Formatter.Serialize(OutputStream, Targets);
        } catch (SerializationException ex) {
            //(Likely Failed to Mark Type as Serializable)
            //...
        }
}

Используйте в качестве такового:

[Serializable]
public class Animal
{
    public string Home { get; set; }
}

[Serializable]
public class Person
{
    public string Name { get; set; }
}


public void ExampleUsage() {

    List<Object> SerializeMeBaby = new List<Object> {
        new Animal { Home = "London, UK" },
        new Person { Name = "Skittles" }
    };

    string TargetPath = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
        "Test1.dat");

    SerializeList(SerializeMeBaby, TargetPath);
}
0
ответ дан 24 November 2019 в 13:04
поделиться

Ниже представлен класс Util в моем проекте:

namespace Utils
{
    public static class SerializeUtil
    {
        public static void SerializeToFormatter<F>(object obj, string path) where F : IFormatter, new()
        {
            if (obj == null)
            {
                throw new NullReferenceException("obj Cannot be Null.");
            }

            if (obj.GetType().IsSerializable == false)
            {
                //  throw new 
            }
            IFormatter f = new F();
            SerializeToFormatter(obj, path, f);
        }

        public static T DeserializeFromFormatter<T, F>(string path) where F : IFormatter, new()
        {
            T t;
            IFormatter f = new F();
            using (FileStream fs = File.OpenRead(path))
            {
                t = (T)f.Deserialize(fs);
            }
            return t;
        }

        public static void SerializeToXML<T>(string path, object obj)
        {
            XmlSerializer xs = new XmlSerializer(typeof(T));
            using (FileStream fs = File.Create(path))
            {
                xs.Serialize(fs, obj);
            }
        }

        public static T DeserializeFromXML<T>(string path)
        {
            XmlSerializer xs = new XmlSerializer(typeof(T));
            using (FileStream fs = File.OpenRead(path))
            {
                return (T)xs.Deserialize(fs);
            }
        }

        public static T DeserializeFromXml<T>(string xml)
        {
            T result;

            var ser = new XmlSerializer(typeof(T));
            using (var tr = new StringReader(xml))
            {
                result = (T)ser.Deserialize(tr);
            }
            return result;
        }


        private static void SerializeToFormatter(object obj, string path, IFormatter formatter)
        {
            using (FileStream fs = File.Create(path))
            {
                formatter.Serialize(fs, obj);
            }
        }
    }
}
2
ответ дан 24 November 2019 в 13:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: