2

Я пытаюсь сохранить список IFilter (типа Interface), который применяется к изображению с использованием сериализации XML, так что пользователь может редактировать одно и то же изображение с того места, где он остановился.Как сериализовать Список <IFilter> (Nokia Imaging SDK)?

[XmlRoot] 
public class ImageProperties 
{ 
    public string ImageName { get; set; } 
    public string ImageFilePath { get; set; } 
    public List<IFilter> Filters { get; set; } 
} 

Возможно ли это? Есть ли другая альтернатива сделать то же самое?

ответ

1

Вы можете использовать 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;} 
} 

Вы можете использовать следующую сериализацию и deserialise два различных типа фильтра 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> 
+0

Что делать, если IFilter имеет переменные, которые зависят от выбора пользователя? Каждый IFilter имеет разные переменные. – venu238

+0

Вызывается сериализатор для реального типа IFilter, поэтому, если предположить, что он записывает всю соответствующую информацию об этом конкретном типе фильтра, вся уникальная информация для каждого типа фильтра сохраняется и восстанавливается с этим. Я расширил этот пример, чтобы показать это. – steve16351

1

Нет. Экземпляры интерфейса не могут быть сериализованы. Он не знает, как реализовать «десериализацию». В этом случае для этого потребуется конкретный класс или пользовательская сериализация.