Как сериализовать список<IFilter> (Nokia Imaging SDK)?
Я пытаюсь сохранить список IFilter(типа Interface), который применяется к изображению с использованием XML-сериализации, чтобы пользователь мог редактировать то же изображение с того места, где он остановился.
[XmlRoot]
public class ImageProperties
{
public string ImageName { get; set; }
public string ImageFilePath { get; set; }
public List<IFilter> Filters { get; set; }
}
Это возможно? Есть ли другая альтернатива, чтобы сделать то же самое?
2 ответа
Вы могли бы использовать IXmlSerializable
чтобы достичь этого.. при условии, что вы можете изменить ImageProperties
учебный класс.
После сериализации вы можете получить тип, просматривая каждый экземпляр фильтра и запрашивая его. Вы можете сохранить эту информацию о типе в XML, чтобы при ее прочтении вы знали, какой это тип, а затем просто вызывали сериализатор XML по умолчанию для каждого фильтра.
Вот возможная реализация.
public class ImageProperties : IXmlSerializable
{
public string ImageName { get; set; }
public string ImageFilePath { get; set; }
public List<IFilter> Filters { get; set; }
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
string startEle = reader.Name;
reader.ReadStartElement();
Filters = new List<IFilter>();
do
{
switch (reader.Name)
{
case "imgName":
ImageName = reader.ReadElementContentAsString();
break;
case "imgFilePath":
ImageFilePath = reader.ReadElementContentAsString();
break;
case "filters":
reader.ReadStartElement("filters");
while (reader.Name.Equals("iFilter"))
{
XmlSerializer filterSerializer = new XmlSerializer(Type.GetType(reader.GetAttribute("type")));
reader.ReadStartElement("iFilter");
Filters.Add((IFilter)filterSerializer.Deserialize(reader));
reader.ReadEndElement();
}
reader.ReadEndElement();
break;
default:
reader.ReadOuterXml();
break;
}
} while (reader.Name != startEle);
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteElementString("imgName", ImageName);
writer.WriteElementString("imgFilePath", ImageFilePath);
writer.WriteStartElement("filters");
foreach (IFilter filter in Filters)
{
writer.WriteStartElement("iFilter");
writer.WriteAttributeString("type", filter.GetType().FullName);
XmlSerializer filterSerializer = new XmlSerializer(filter.GetType());
filterSerializer.Serialize(writer, filter);
writer.WriteEndElement();
}
writer.WriteEndElement();
}
}
Если у вас есть разные типы фильтров, по умолчанию вызывается сериализатор реального типа, поэтому их уникальные свойства будут записаны.
Например, с этими классами фильтра доступны:
public interface IFilter
{
string SomeCommonProp { get; set;}
}
[XmlRoot("myFilter")]
public class MyFilter : IFilter
{
[XmlElement("somemyFilterProp")]
public string SomeMyFilterProp { get; set; }
[XmlElement("someCommonProp")]
public string SomeCommonProp { get; set;}
}
[XmlRoot("myOtherFilter")]
public class MyOtherFilter : IFilter
{
[XmlElement("someOtherFilterProp")]
public string SomeOtherFilterProp { get; set; }
[XmlElement("someCommonProp")]
public string SomeCommonProp { get; set;}
}
Вы можете использовать следующее для сериализации и десериализации двух разных типов фильтров в IFilters в xml.
static void Main(string[] args)
{
ImageProperties props = new ImageProperties();
props.ImageName = "img.png";
props.ImageFilePath = "c:\\temp\\img.png";
props.Filters = new List<IFilter>();
props.Filters.Add(new MyFilter() { SomeMyFilterProp = "x", SomeCommonProp ="p" });
props.Filters.Add(new MyOtherFilter() { SomeOtherFilterProp = "y", SomeCommonProp ="p" });
XmlSerializer s = new XmlSerializer(typeof(ImageProperties));
using (StreamWriter writer = new StreamWriter(@"c:\temp\imgprops.xml"))
s.Serialize(writer, props);
using (StreamReader reader = new StreamReader(@"c:\temp\imgprops.xml"))
{
object andBack = s.Deserialize(reader);
}
Console.ReadKey();
}
Это создает XML, который выглядит следующим образом.
<?xml version="1.0" encoding="utf-8"?>
<ImageProperties>
<imgName>img.png</imgName>
<imgFilePath>c:\temp\img.png</imgFilePath>
<filters>
<iFilter type="SomeNameSpace.Whatever.MyFilter">
<myFilter xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<somemyFilterProp>x</somemyFilterProp>
<someCommonProp>p</someCommonProp>
</myFilter>
</iFilter>
<iFilter type="SomeNameSpace.Whatever.MyOtherFilter">
<myOtherFilter xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<someOtherFilterProp>y</someOtherFilterProp>
<someCommonProp>p</someCommonProp>
</myOtherFilter>
</iFilter>
</filters>
</ImageProperties>
Нет. Экземпляры интерфейса не могут быть сериализованы. Он не знает реализацию "десериализации" для. В этом случае потребуется конкретный класс или пользовательская сериализация.