【问题标题】:Class Serialization To XML类序列化到 XML
【发布时间】:2014-01-07 23:59:15
【问题描述】:

鉴于以下类设计:

 public class AllUserCollections
    {
        public List<UserCollection> UserCollections { get; set; }

        public AllUserCollections()
        {
            this.UserCollections = new List<UserCollection> ();
        }
    }

    public class UserCollection
    {
        public string UserGroup { get; set; }
        public Dictionary<int,User> Users { get; set; }

        public UserCollection(string userGroup)
        {
            this.UserGroup = userGroup;
            this.Users = new Dictionary<int, User> ();
        }
    }

    public class User
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string Location { get; set; }
        public AgeGroup UserAgeGroup { get; set; }
    }

    public enum AgeGroup
    {
        Twenties,
        Thirties,
        Fourties,
    }

如何使用现有的序列化类将其序列化为 XML?

public static class HardDriveService
    {
        private static string docsFolderPath = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
        private const string fileName = "AllUserCollections.xml";
        private static string filePath = Path.Combine(docsFolderPath, fileName);

        private static bool FileExists(string fullFilePath)
        {
            if (File.Exists (fullFilePath)) 
                return true;

            return false;
        }

        public static void Save(AllUserCollections allUserCollections)
        {
            if (FileExists(filePath))
            {
                File.Delete (filePath);
            }

            XmlSerializer serializer = new XmlSerializer(allUserCollections.GetType());
            using(StreamWriter writer = new StreamWriter(filePath))
            {
                serializer.Serialize(writer.BaseStream, allUserCollections);
            }
        }

        public static AllUserCollections Read()
        {
            AllUserCollections allUserCollections = new AllUserCollections();
            XmlSerializer serializer = new XmlSerializer(allUserCollections.GetType());

            if (FileExists(filePath))
            {
                StreamReader reader = new StreamReader(filePath);
                object deserialized = serializer.Deserialize(reader.BaseStream);
                allUserCollections = (AllUserCollections)deserialized;
            }

            return allUserCollections;
        }


    }//End of class.

问题

我的代码似乎在这一行失败 -

XmlSerializer serializer = new XmlSerializer(allUserCollections.GetType());

我想知道这是否与需要明确标记为“可序列化”的类有关?我该怎么做?

用法 此代码将在 iphone 上运行,并将应用程序直接保存/读取到 iPhone 硬盘上的 XML。

【问题讨论】:

标签: c# xml serialization xml-serialization


【解决方案1】:

XMLSerializer 不支持开箱即用的字典。您的 UserCollection 类有一个 Dictionary。有关解决方法,请参阅此链接。 Why doesn't XmlSerializer support Dictionary?

除此之外,XMLSerializer 要求您的类具有默认构造函数(UserCollection 和 User 没有)并且每个类都必须具有 [Serializable] 属性。

【讨论】:

    【解决方案2】:

    您可以使用XElement 来构建 XML 格式。您可以按照以下方式使用它们:

    public static XElement ToXml(this User user)
    {
        if (user == null)
        {
            throw new ArgumentException("User can not be null.");
        }
    
        XElement userElement = new XElement("User");
        userElement.Add(new XElement("ID", user.ID));
        userElement.Add(new XElement("Name", user.Name));
        userElement.Add(new XElement("Location", user.Location));
        userElement.Add(new XElement("UserAgeGroup", user.UserAgeGroup));
    
        return userElement;
    }
    
    public static string ToXml(this UserCollection userCollection)
    {
        if (userCollection == null)
        {
            throw new ArgumentException("UserCollection can not be null.");
        }
    
        XElement userCollectionElement = new XElement("UserCollection");
        userCollectionElement.Add(new XElement("UserGroup", userCollection.UserGroup));
        userCollectionElement.Add(new XElement("Users", 
                                               userCollection.Users.Select(x => new XElement("User", x.ToXml()));
    
        return userCollectionElement;
    }
    

    XElement 上调用 .ToString() 应该会给你一个 xml 格式的字符串。

    【讨论】:

      【解决方案3】:

      完整的工作解决方案

      数据模型

      using System;
      using System.Collections.Generic;
      
      namespace iPhoneHardDriveCRUDPrototype
      {
          [Serializable]
          public class AllUserCollections
          {
              public List<UserCollection> UserCollections { get; set; }
      
              public AllUserCollections()
              {
                  this.UserCollections = new List<UserCollection> ();
              }
          }
      
          [Serializable]
          public class UserCollection
          {
              public string UserGroup { get; set; }
              public SerializableDictionary<int,User> Users { get; set; }
      
              public UserCollection()
              {
                  this.Users = new SerializableDictionary<int, User> ();
              }
      
              public UserCollection(string userGroup)
              {
                  this.UserGroup = userGroup;
                  this.Users = new SerializableDictionary<int, User> ();
              }
          }
      
          [Serializable]
          public class User
          {
              public int ID { get; set; }
              public string Name { get; set; }
              public string Location { get; set; }
              public AgeGroup UserAgeGroup { get; set; }
      
              public User()
              {
      
              }
          }
      
          [Serializable]
          public enum AgeGroup
          {
              Twenties,
              Thirties,
              Fourties,
          }
      }
      

      可序列化字典

      using System;
      using System.Xml.Serialization;
      using System.Collections.Generic;
      
      namespace iPhoneHardDriveCRUDPrototype
      {
          [XmlRoot("dictionary")] 
          public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable 
          { 
              public System.Xml.Schema.XmlSchema GetSchema() 
              { 
                  return null; 
              }
      
              public void ReadXml(System.Xml.XmlReader reader) 
              { 
                  XmlSerializer keySerializer = new XmlSerializer(typeof(TKey)); 
                  XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
      
                  bool wasEmpty = reader.IsEmptyElement; 
                  reader.Read();
      
                  if (wasEmpty) 
                      return;
      
                  while (reader.NodeType != System.Xml.XmlNodeType.EndElement) 
                  { 
                      reader.ReadStartElement("item"); 
                      reader.ReadStartElement("key"); 
                      TKey key = (TKey)keySerializer.Deserialize(reader); 
                      reader.ReadEndElement(); 
                      reader.ReadStartElement("value"); 
                      TValue value = (TValue)valueSerializer.Deserialize(reader); 
                      reader.ReadEndElement(); 
                      this.Add(key, value); 
                      reader.ReadEndElement(); 
                      reader.MoveToContent(); 
                  } 
                  reader.ReadEndElement(); 
              }
      
              public void WriteXml(System.Xml.XmlWriter writer) 
              { 
                  XmlSerializer keySerializer = new XmlSerializer(typeof(TKey)); 
                  XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));
      
                  foreach (TKey key in this.Keys) 
                  { 
                      writer.WriteStartElement("item"); 
                      writer.WriteStartElement("key"); 
                      keySerializer.Serialize(writer, key); 
                      writer.WriteEndElement(); 
                      writer.WriteStartElement("value"); 
                      TValue value = this[key]; 
                      valueSerializer.Serialize(writer, value); 
                      writer.WriteEndElement(); 
                      writer.WriteEndElement(); 
                  } 
              }
      
      
      
          }//End of Class....
      }
      

      序列化器

      using System;
      using System.IO;
      using System.Xml.Serialization;
      using System.Reflection;
      using System.Collections.Generic;
      
      namespace iPhoneHardDriveCRUDPrototype
      {
          public static class HardDriveService
          {
              private static string docsFolderPath = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
              private const string fileName = "AllUserCollections.xml";
              private static string filePath = Path.Combine(docsFolderPath, fileName);
      
              private static bool FileExists(string fullFilePath)
              {
                  if (File.Exists (fullFilePath)) 
                      return true;
      
                  return false;
              }
      
              public static void Save(AllUserCollections allUserCollections)
              {
                  if (FileExists(filePath))
                  {
                      File.Delete (filePath);
                  }
      
                  XmlSerializer serializer = new XmlSerializer(allUserCollections.GetType());
                  using(StreamWriter writer = new StreamWriter(filePath))
                  {
                      serializer.Serialize(writer.BaseStream, allUserCollections);
                  }
              }
      
              public static AllUserCollections Read()
              {
                  AllUserCollections allUserCollections = new AllUserCollections();
                  XmlSerializer serializer = new XmlSerializer(allUserCollections.GetType());
      
                  if (FileExists(filePath))
                  {
                      StreamReader reader = new StreamReader(filePath);
                      object deserialized = serializer.Deserialize(reader.BaseStream);
                      allUserCollections = (AllUserCollections)deserialized;
                  }
      
                  return allUserCollections;
              }
      
      
          }//End of class.
      }
      

      【讨论】:

      • 不,这不是一个完整的工作解决方案,因为您无法反序列化字典并且列表类型我使用 datacontractserializer 的解决方案会更好地工作
      • DataContractSerializer 不受 MonoTouch 支持。是的,我发布的可序列化字典类确实有效。
      • 首先你没有添加moonotouch标签第二个DataContractSerializer支持Monotouch
      【解决方案4】:

      在这里您有 2 个选择 XmlSerializer(不适用于 Dictionary 或 List 类型的反序列化),或者您可以使用在 .net 3.0 中添加的 DataContractSerializer,这里有很多优点:形成 post

      • 针对速度进行了优化(通常比 XmlSerializer 快 10% 左右)

      • 在“选择加入”中 - 只有您明确标记为 [DataMember] 的内容才会被序列化

      • 不支持 XML 属性(出于速度原因)

      注意:您应该添加对 C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\System.Runtime.Serialization.dll 的引用

      //to serialize 
              SerializeHelper.Serialize("your filename" ,new AllUserCollections());
      // deserialize
              var usertCollections = SerializeHelper.Deserialize<AllUserCollections>("yourfile name"); 
      
      
      //code 
       [DataContract]
          public class AllUserCollections
          {
              public List<UserCollection> UserCollections { get; set; }
      
              public AllUserCollections()
              {
                  this.UserCollections = new List<UserCollection>();
              }
          }
          [DataContract()]
          public class UserCollection
          {
               [DataMember]
              public string UserGroup { get; set; }
      
               [DataMember]
              public Dictionary<int, User> Users { get; set; }
      
              public UserCollection(string userGroup)
              {
                  this.UserGroup = userGroup;
                  this.Users = new Dictionary<int, User>();
              }
          }
          [DataContract()]
          public class User
          {   [DataMember]
              public int ID { get; set; }
               [DataMember]
              public string Name { get; set; }
               [DataMember]
              public string Location { get; set; }
               [DataMember]
              public AgeGroup UserAgeGroup { get; set; }
          }
           [DataContract]
          public enum AgeGroup
          {
              Twenties,
              Thirties,
              Fourties,
          }
          public  static class  SerializeHelper
          {
               public static void Serialize<T>(string fileName, T obj)
          {
              using (FileStream writer = new FileStream(fileName, FileMode.Create))
              {
               DataContractSerializer ser =
                  new DataContractSerializer(typeof(T));
              ser.WriteObject(writer, obj);
              writer.Close();   
              }
      
      
          }
      
          public static T Deserialize<T>(string fileName)
          {
              T des;
              using (FileStream fs = new FileStream(fileName,FileMode.Open))
              {
              XmlDictionaryReader reader =
                  XmlDictionaryReader.CreateTextReader(fs, new XmlDictionaryReaderQuotas());
              DataContractSerializer ser = new DataContractSerializer(typeof(T));
              des =
                  (T)ser.ReadObject(reader, true);
              reader.Close();
              fs.Close(); 
      
              }
      
              return des;
          }
          }
      

      【讨论】:

      • 什么是 DataContractSerializer?
      • @JohnSaunders 我太忙了,很快就发布了答案
      • @JulieShannon:好吧,在你有时间解决这个问题之前,我太忙了,无法撤销反对票 :-)
      • @JohnSaunders 你能恢复你的反对票吗,现在看起来好多了:)
      • 我的意思是 using 块在 FileStream 和其他任何实现 IDisposable 的块。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-13
      • 2021-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多