簡體   English   中英

如何序列化/反序列化List <class object> 與protobuf?

[英]how to serialize / deserialize List<class object> with protobuf?

我想序列化List<ArchiveData>但它幾乎總是失敗。 Protobuff拋出以下異常:

無效的線型; 這通常意味着您在不截斷或設置長度的情況下覆蓋了文件; 看到使用Protobuf-net,我突然得到一個關於未知線型的例外

我已閱讀帖子但仍無法找到解決方案。 我如何序列化和反序列化?

我的班級和結構:

[Serializable, ProtoContract(Name = @"Archive"), ProtoInclude(1, typeof(List<ArchiveData>))]
public partial class Archive : IExtensible
{
    [ProtoMember(1, IsRequired = true, OverwriteList = true, Name = @"data", DataFormat = DataFormat.Default)]
    public List<ArchiveData> data { get; set; }

    public Archive()
    {
        data = new List<ArchiveForm.ArchiveData>();
    }

    private IExtension extensionObject;
    IExtension IExtensible.GetExtensionObject(bool createIfMissing)
    {
        return Extensible.GetExtensionObject(ref extensionObject, createIfMissing);
    }
}

public struct ArchiveData
{
    [ProtoMember(1, IsRequired = false, OverwriteList = true, Name = @"sourcefolder", DataFormat = DataFormat.Default)]
    [global::System.ComponentModel.DefaultValue("")]
    public string sourcefolder { get; set; }

    [ProtoMember(2, IsRequired = false, OverwriteList = true, Name = @"destinationfolder", DataFormat = DataFormat.Default)]
    [global::System.ComponentModel.DefaultValue("")]
    public string destinationfolder { get; set; }

    [ProtoMember(3, IsRequired = false, OverwriteList = true, Name = @"period", DataFormat = DataFormat.FixedSize)]
    [global::System.ComponentModel.DefaultValue((int)0)]
    public int period { get; set; }

    public ArchiveData(string sfolder = "", string dfolder = "", int priod = 0)
    {
        sourcefolder = sfolder;
        destinationfolder = dfolder;
        period = priod;
    }
}

我用以下方法序列化:

public static void Refresh(ref Archive arc)
{
    if (File.Exists(probuffile))
    {
        using (var fs = File.OpenRead(probuffile))
        {
            arc = Serializer.Deserialize<Archive>(fs);
        }
    }
}

我用以下方法反序列化:

public static void Update(Archive arc)
{
    using (var fs = File.Create(probuffile))
    {
        Serializer.Serialize<Archive>(fs, arc);
        fs.SetLength(fs.Position);
    }
}

我用它:

Archive archive = new Archive();
//Add some ArchiveData.
Refresh(ref archive);

- - - - - - - - - - - - - - - 編輯 - - - - - - - - - - -----------

添加了此部分以獲取更多信息。 當我像下面的代碼一樣使用SerializeWithLengthPrefix / DeserializeWithLengthPrefix函數時,它每次都適用於我使用Deserialize函數的第一個類。 但是對於我使用Deserialize函數的第二個類,它返回null。

[Serializable, ProtoContract(Name = @"OptionData")]
public class OptionData : IExtensible
{
    [ProtoMember(1, IsRequired = false, OverwriteList = true, Name = @"StartWithWindows", DataFormat = DataFormat.Default)]
    [DefaultValue(false)]
    public bool StartWithWindows { get; set; }

    [ProtoMember(2, IsRequired = false, OverwriteList = true, Name = @"AutoBackup", DataFormat = DataFormat.Default)]
    [DefaultValue(false)]
    public bool AutoBackup { get; set; }

    [ProtoMember(3, IsRequired = false, OverwriteList = true, Name = @"Speed", DataFormat = DataFormat.FixedSize)]
    [DefaultValue((int)0)]
    public int Speed { get; set; }

    private IExtension extensionObject;
    IExtension IExtensible.GetExtensionObject(bool createIfMissing)
    {
        return Extensible.GetExtensionObject(ref extensionObject, createIfMissing);
    }
}

public static void Update(OptionData op)
{
    using (var fs = File.Create(probuffile))
    {
        Serializer.SerializeWithLengthPrefix(fs, op, PrefixStyle.Base128, 3);
    }
}

public static void Update(Archive arc)
{
    using (var fs = File.Create(probuffile))
    {
        Serializer.SerializeWithLengthPrefix<Archive>(fs, arc, PrefixStyle.Base128, 2);
    }
}

public static void Refresh(ref OptionData op)
{
    if (File.Exists(probuffile))
    {
        using (var fs = File.OpenRead(probuffile))
        {
            op = Serializer.DeserializeWithLengthPrefix<OptionData>(fs, PrefixStyle.Base128, 3);
        }
    }
}

public static void Refresh(ref Archive arc)
{
    if (File.Exists(probuffile))
    {
        using (var fs = File.OpenRead(probuffile))
        {
            arc = Serializer.DeserializeWithLengthPrefix<Archive>(fs, PrefixStyle.Base128, 2);
        }
    }
}

我很樂意提供幫助,但我很難讓它失敗。 你說“但它幾乎總是失敗”,但是下面的可運行的控制台exer工作正常,並編寫了大量不同大小的數據:

using ProtoBuf;
using System;
using System.Collections.Generic;
using System.IO;
static class P
{
    static void Main()
    {
        var random = new Random(12345);
        // start with 100
        var archive = CreateData(random, 100);
        Update(archive);
        Refresh(ref archive);

        // make it bigger
        archive = CreateData(random, 200);
        Update(archive);
        Refresh(ref archive);

        // make it smaller
        archive = CreateData(random, 50);
        Update(archive);
        Refresh(ref archive);

        // go wild
        for (int i = 0; i < 1000; i++)
        {
            archive = CreateData(random, random.Next(0, 500));
            Update(archive);
            Refresh(ref archive);
        }

    }
    static Archive CreateData(Random random, int dataCount)
    {
        var archive = new Archive();
        var data = archive.data;
        for (int i = 0; i < dataCount; i++)
        {
            data.Add(new ArchiveData
            {
                period = random.Next(10000),
                sourcefolder = CreateString(random, 50),
                destinationfolder = CreateString(random, 50)
            });
        }
        return archive;
    }

    private static unsafe string CreateString(Random random, int maxLength)
    {
        const string Alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
        int len = random.Next(maxLength + 1);
        char* chars = stackalloc char[len];
        for (int i = 0; i < len; i++)
        {
            chars[i] = Alphabet[random.Next(Alphabet.Length)];
        }
        return new string(chars, 0, len);
    }

    static string probuffile = "my.bin";
    public static void Refresh(ref Archive arc)
    {
        if (File.Exists(probuffile))
        {
            using (var fs = File.OpenRead(probuffile))
            {
                arc = Serializer.Deserialize<Archive>(fs);
                Console.WriteLine("Read: {0} items, {1} bytes", arc.data.Count, fs.Length);
            }
        }
    }

    public static void Update(Archive arc)
    {
        using (var fs = File.Create(probuffile))
        {
            Serializer.Serialize<Archive>(fs, arc);
            fs.SetLength(fs.Position);
            Console.WriteLine("Wrote: {0} items, {1} bytes", arc.data.Count, fs.Length);
        }
    }
}

[Serializable, ProtoContract(Name = @"Archive"), ProtoInclude(1, typeof(List<ArchiveData>))]
public partial class Archive : IExtensible
{
    [ProtoMember(1, IsRequired = true, OverwriteList = true, Name = @"data", DataFormat = DataFormat.Default)]
    public List<ArchiveData> data { get; set; }

    public Archive()
    {
        data = new List<ArchiveData>();
    }

    private IExtension extensionObject;
    IExtension IExtensible.GetExtensionObject(bool createIfMissing)
    {
        return Extensible.GetExtensionObject(ref extensionObject, createIfMissing);
    }
}
[ProtoContract]
public struct ArchiveData
{
    [ProtoMember(1, IsRequired = false, OverwriteList = true, Name = @"sourcefolder", DataFormat = DataFormat.Default)]
    [global::System.ComponentModel.DefaultValue("")]
    public string sourcefolder { get; set; }

    [ProtoMember(2, IsRequired = false, OverwriteList = true, Name = @"destinationfolder", DataFormat = DataFormat.Default)]
    [global::System.ComponentModel.DefaultValue("")]
    public string destinationfolder { get; set; }

    [ProtoMember(3, IsRequired = false, OverwriteList = true, Name = @"period", DataFormat = DataFormat.FixedSize)]
    [global::System.ComponentModel.DefaultValue((int)0)]
    public int period { get; set; }

    public ArchiveData(string sfolder = "", string dfolder = "", int priod = 0)
    {
        sourcefolder = sfolder;
        destinationfolder = dfolder;
        period = priod;
    }
}

我猜你的真實代碼和上面的例子之間的區別是:這也是問題的原因。 如果你幫助找到不同的東西,我會非常樂意為你提供合理的幫助。

作為次要注意事項:使用Create時實際上不需要設置長度,因為這顯然是“丟棄任何現有數據”。 你需要擔心的時間長短的主要時間是當人們使用OpenWrite寫在現有的文件,然后寫入數據較少比已經在那里了。 但是在Create之后顯式設置長度沒有問題

protobuf 和列表<object> - 如何序列化/反序列化?<div id="text_translate"><p> 我有一個List&lt;object&gt; ,其中包含不同類型的對象,例如整數、字符串和自定義類型。 所有自定義類型都經過 protobuf 調整。 我現在想做的是用 protobuf.net 序列化/反序列化這個列表。 到目前為止,我懷疑我必須顯式聲明每種類型,不幸的是,這些混合列表構造不可能做到這一點。 因為二進制格式化程序在做這些事情時沒有問題,我希望我錯過了一些東西,你可以幫助我。 所以我的問題是如何處理 protobuf.net 中的對象。</p></div></object>

[英]protobuf and List<object> - how to serialize / deserialize?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM