【问题标题】:In C# how can I serialize a List<int> to a byte[] in order to store it in a DB field?在 C# 中,如何将 List<int> 序列化为 byte[] 以便将其存储在 DB 字段中?
【发布时间】:2011-02-01 07:40:08
【问题描述】:

在 C# 中,如何将 List&lt;int&gt; 序列化为 byte[] 以便将其存储在 DB 字段中?

我知道如何序列化到磁盘上的文件,但是我如何只序列化到变量呢?

这是我序列化到磁盘的方式:

            List<int> l = IenumerableofInts.ToList();
            Stream s = File.OpenWrite("file.bin");
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(s, lR);
            s.Close();

我确定它大致相同,但我无法理解它。

【问题讨论】:

    标签: c# generics list serialization


    【解决方案1】:

    使用MemoryStream 代替文件流:

    Stream s = new MemoryStream();
    

    这会将数据放在s 变量中,您可以稍后在应用程序中读取该变量。

    为了从中读取,您需要将 Position 设置为 0,因此搜索将从流的开头开始(如果以块的形式读取),或者在其上使用 ToArray() 来检索完整内容。

    【讨论】:

    • 对于 MemoryStream 的新手来说,重要的是还要指出您必须在读取之前将 Position 设置回 0。这经常被忽视,并导致新开发者有些摸不着头脑。
    • @Sam - 感谢您的评论。已使用此信息更新答案。
    • @Sam。不正确。无论位置如何,都可以使用.ToArray()方法获取MemoryStream的内容。
    • @Jason Punyon, .ToArray() 会将数据复制到一个新数组中,而将 .Position 设置为零可以让您直接访问基础数据而无需额外的副本。
    • @Sam:同意。我认为获取字节的数组表示(这就是 Q 的含义)并立即处理流会更容易。
    【解决方案2】:

    坦率地说:我会将它们放在数据库中的另一个表中,该表与其父记录具有一对多的外键关系。

    这样,您可以对它们进行正常的数据库操作,例如根据子表中的整数来检索父记录。

    【讨论】:

    • +1。即使您将其序列化为 XML 并将其存储为 XML 列类型(在 SQL Server 中),搜索/检索/报告仍然比使用二进制序列化更好。而规范化表通常是比这更好的选择。
    【解决方案3】:

    就个人而言,我不会为此目的使用BinaryFormatter - 它是特定于实现的并且过于昂贵。我很想(其中之一):

    1:使用 BinaryWriter / BinaryReader 手动完成(但请注意,这很容易从任何 API 中解释):

        // note I've used arrays in the example; lists are identical
        int[] data = { 1, 2, 3, 4, 5 };
        byte[] raw;
        using (var ms = new MemoryStream())
        using (var writer = new BinaryWriter(ms))
        {
            writer.Write(data.Length);
            foreach(int i in data) {
                writer.Write(i);
            }
            writer.Close();
            raw = ms.ToArray();
        }
        // read it back
        using (var ms = new MemoryStream(raw))
        using (var reader = new BinaryReader(ms))
        {
            int count = reader.ReadInt32();
            data = new int[count];
            for (int i = 0; i < count; i++)
            {
                data[i] = reader.ReadInt32();
            }
        }
    

    或2:使用与实现无关的序列化格式,例如protobuf;这里我使用的是 protobuf-net

        int[] data = { 1, 2, 3, 4, 5 };
        byte[] raw;
        using (var ms = new MemoryStream()) {
            Serializer.Serialize(ms, data);
            raw = ms.ToArray();
        }
        // read it back
        using (var ms = new MemoryStream(raw)) {
            data = Serializer.Deserialize<int[]>(ms);
        }
    

    请注意,(1) 示例使用 24 字节(6 * 4 字节); (2) 使用 10 个字节(部分原因是数字很简单,但实际上 protobuf 有一些我们甚至没有在这里使用的技巧(例如“打包”数据))。

    【讨论】:

      【解决方案4】:

      使用通用序列化器

      private static string SerializeObject<T>(T source)
      {
          var serializer = new XmlSerializer(typeof(T));
      
          using (var sw = new System.IO.StringWriter())
          using (var writer = new XmlTextWriter(sw))
          {
              serializer.Serialize(writer, source);
              return sw.ToString();
          }
      }
      

      http://weblogs.asp.net/rajbk/archive/2009/10/04/xmlserializer-and-invalid-xml.aspx

      【讨论】:

      • @Jason - 在网络上,他们之间的数量并不大。
      • @Marc Gravell:我不会在序列化问题上与大师角力,但即使是一个具有大量详细命名属性的对象列表?
      • @Jason - 哦,绝对 xml 太过分了 - 哎呀,tsv / csv 等会更容易。我的观点很简单,字符串和字节之间几乎没有根本区别。显然,一个很大程度上是另一个的子集,但你知道我的意思。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-20
      • 2013-10-08
      • 1970-01-01
      • 1970-01-01
      • 2011-08-19
      • 1970-01-01
      相关资源
      最近更新 更多