почему не что-то вроде этого:
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#
Вы не можете сериализовать коллекцию объектов без указания ожидаемых типов. Вы должны передать список ожидаемых типов в конструктор 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
{
}
Я думаю, что лучше всего использовать методы с общими аргументами, например:
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;
}
Я думаю, что подход Дреаса приемлем. Однако альтернативой этому является наличие некоторых статических вспомогательных методов и реализация 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();
}
См. Введение в сериализацию XML :
Элементы, которые можно сериализовать
Следующие элементы можно сериализовать с помощью XmlSerializer class:
- Общедоступные свойства чтения / записи и поля общедоступных классов
- Классы, реализующие
ICollection
илиIEnumerable
XmlElement
объектыобъекты XmlNode
DataSet
объекты
В частности, ISerializable
или атрибут [Serializable]
не имеют значения.
Теперь, когда вы сообщили нам, в чем заключается ваша проблема. («это не работает» не является формулировкой проблемы), вы можете получить ответы на вашу реальную проблему вместо предположений.
Когда вы сериализуете коллекцию типа, но на самом деле сериализуете коллекцию экземпляров производные типы, вам необходимо сообщить сериализатору, какие типы вы на самом деле будете сериализовать. Это также верно для коллекций объекта
.
Вам необходимо использовать XmlSerializer (Type,
Если требования вывода 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);
}
Ниже представлен класс 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);
}
}
}
}