protobuf-net不支持指定的方法

时间:2012-10-23 00:04:32

标签: c# serialization .net-4.0 protobuf-net

我最近决定使用protobuf-net序列化我的应用程序使用的大型纯文本数据文件,以查看解析纯文本数据是否有任何性能提升。

数据类:

[ProtoContract]
public class ClimateFile : BaseModel
{
    #region Properties
    [ProtoMember(1)]
    public double Latitude { get { return GetValue(() => Latitude); } private set { SetValue(() => Latitude, value); } }

    [ProtoMember(2)]
    public double Longitude { get { return GetValue(() => Longitude); } private set { SetValue(() => Longitude, value); } }

    [ProtoMember(3)]
    public string Notes { get { return GetValue(() => Notes); } set { SetValue(() => Notes, value); } }

    [ProtoMember(4)]
    public DateTime MinDate { get { return GetValue(() => MinDate); } private set { SetValue(() => MinDate, value); } }

    [ProtoMember(5)]
    public DateTime MaxDate { get { return GetValue(() => MaxDate); } private set { SetValue(() => MaxDate, value); } }

    [ProtoMember(6)]
    public List<ClimateDailyData> DailyData { get { return GetValue(() => DailyData); } private set { SetValue(() => DailyData, value); } }
    #endregion

    #region Method
    public static ClimateFile Load(string filePath)
    {
        try
        {
            var ext = Path.GetExtension(filePath).ToUpper();
            if (ext == ".P51")
                return new ClimateFile(filePath);
            else if (ext == ".P51X")
            {
                ClimateFile climateFile;
                using (var file = File.OpenRead(filePath))
                {
                    climateFile = Serializer.Deserialize<ClimateFile>(file);
                }
                return climateFile;
            }
        }
        catch (Exception e)
        {
            throw new InvalidDataException(String.Format("The file \"{0}\" could not be opened, {1}", filePath, ExceptionUtilities.JoinExceptionMessages(e)));
        }

        throw new ArgumentException("filePath was not a .P51 or .P51X file.");
    }

    public void LoadP51File(string filePath)
    {
        List<string[]> lines = GetFileLines(filePath);
        Latitude = double.Parse(lines[0][0]);
        Longitude = double.Parse(lines[0][1]);
        for (int i = 2; i < lines[0].Length; ++i)
            Notes += String.Format("{0} ", lines[0][i]);
        MinDate = GetDate(lines[2][0]);
        MaxDate = GetDate(lines[lines.Count - 1][0]);

        // Parse daily data
        lines.RemoveRange(0, 2);
        var dailyData = lines.Select(row => new ClimateDailyData()
            {
                DataDate = GetDate(row[0]),
                MaxTemperature = double.Parse(row[2]),
                MinTemperature = double.Parse(row[3]),
                Rainfall = double.Parse(row[4]),
                Evaporation = double.Parse(row[5]),
                SolarRadiation = double.Parse(row[6])
            }).ToList();
        DailyData = dailyData;
    }

    public void SaveP51XFile(string filePath)
    {
        using (var file = File.Create(filePath))
        {
            Serializer.Serialize<ClimateFile>(file, this);
        }
    }

    public List<string[]> GetFileLines(string filePath)
    {
        var rows = new List<string[]>();
        var cells = new List<string>();
        var cell = new StringBuilder();
        using (var fs = new BufferedStream(File.OpenRead(filePath)))
        {
            int buffer;
            while ((buffer = fs.ReadByte()) != -1)
            {
                char nextChar = (char)buffer;

                if (nextChar >= '!') // If the character is a non-whitespace printable character
                {
                    cell.Append(nextChar);
                    continue;
                }

                if (nextChar == ' ' || nextChar == '\t')
                {
                    if (cell.Length > 0)
                    {
                        cells.Add(cell.ToString());
                        cell.Clear();
                    }
                    continue;
                }

                if (nextChar == '\r' || nextChar == '\n')
                {
                    if (cell.Length > 0)
                    {
                        cells.Add(cell.ToString());
                        cell.Clear();
                    }
                    if (cells.Count > 0)
                    {
                        rows.Add(cells.ToArray());
                        cells.Clear();
                    }
                    continue;
                }
                throw new InvalidDataException("The climate file contains unknown characters.");
            }

            if (cell.Length > 0)
                cells.Add(cell.ToString());
            if (cells.Count > 0)
                rows.Add(cells.ToArray());
        }
        return rows;
    }

    public DateTime GetDate(string date)
    {
        return DateTime.ParseExact(date, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None);
    }

    public override void Dispose()
    {
        if (Disposed)
            return;
        if (DailyData != null)
            foreach (ClimateDailyData dailyData in DailyData)
                dailyData.Dispose();
        base.Dispose();
    }
    #endregion

    #region Initialization
    public ClimateFile()
    {
    }

    public ClimateFile(string filePath)
    {
        LoadP51File(filePath);
    }
    #endregion
}

收集数据类:

    [ProtoContract]
public class ClimateDailyData : BaseModel
{
    [ProtoMember(1)]
    public DateTime DataDate { get { return GetValue(() => DataDate); } set { SetValue(() => DataDate, value); } }

    [ProtoMember(2)]
    public int JulianDay { get { return DataDate.DayOfYear; } }

    [ProtoMember(3)]
    public double MaxTemperature { get { return GetValue(() => MaxTemperature); } set { SetValue(() => MaxTemperature, value); } }

    [ProtoMember(4)]
    public double MinTemperature { get { return GetValue(() => MinTemperature); } set { SetValue(() => MinTemperature, value); } }

    [ProtoMember(5)]
    public double Rainfall { get { return GetValue(() => Rainfall); } set { SetValue(() => Rainfall, value); } }

    [ProtoMember(6)]
    public double Evaporation { get { return GetValue(() => Evaporation); } set { SetValue(() => Evaporation, value); } }

    [ProtoMember(7)]
    public double SolarRadiation { get { return GetValue(() => SolarRadiation); } set { SetValue(() => SolarRadiation, value); } }
}

序列化命令:

public ICommand ImportP51
    {
        get
        {
            return new RelayCommand(delegate
                {
                    OpenFileDialog openDialogue = new OpenFileDialog()
                    {
                        AddExtension = true,
                        CheckPathExists = true,
                        CheckFileExists = true,
                        DefaultExt = ".p51",
                        Filter = "Climate Files|*.p51",
                        InitialDirectory = DataPath,
                        Multiselect = false,
                        Title = "Select a File to Open"
                    };

                    if ((bool)openDialogue.ShowDialog())
                    {
                        string filePath = String.Empty;
                        try
                        {
                            filePath = openDialogue.FileName;
                            var climate = new Climate();
                            climate.FilePath = filePath;
                            var savePath = String.Format("{0}\\{1}.p51x", ClimateDataPath, Path.GetFileNameWithoutExtension(filePath));
                            climate.FileData.SaveP51XFile(savePath);
                        }
                        catch (Exception e)
                        {
                            MessageBox.Show(String.Format("The file \"{0}\" could not be opened, {1}", filePath, ExceptionUtilities.JoinExceptionMessages(e)), "Invalid File");
                        }
                    }
                });
        }
    }

执行ImportP51时,我得到异常“不支持指定方法”,我使用的是2012年10月12日发布的protobuf-net V2 r594,我正在考虑尝试使用其中一个以前的版本,如果我无法使用此版本。有人可以告诉我我做错了吗?

1 个答案:

答案 0 :(得分:3)

我尝试通过使用自动实现的属性并为列表添加初始值设定项来重建代码的工作版本(因为我没有BaseModel) }),并从谷歌代码明确引用r594。我得到的唯一错误是:

  

无法将更改应用于属性ClimateDailyData.JulianDay

这是有道理的,因为它无法正确地将数据反序列化为只读属性,所以我从那个中删除了序列化标记:

DailyData

之后工作正常。由于我没有你的命令框架,我有:

// [ProtoMember(2)] removed - serialized implicitly via DataData
public int JulianDay { get { return DataDate.DayOfYear; } }

其中static class Program { static void Main() { var climateFile = new ClimateFile(); climateFile.InitSomeDataForSerialization(); climateFile.SaveP51XFile("foo.P51X"); var clone = ClimateFile.Load("foo.P51X"); } } 只设置了一些值(因为它们有私有设置器,我不能在InitSomeDataForSerialization中执行此操作):

Main

而且......它有效。

在预感中,我检查了如果您引用“CoreOnly”而不是“Full”会发生什么,但由于public void InitSomeDataForSerialization() { Longitude = 10; Latitude = 4; Notes = "Test"; DailyData.Add( new ClimateDailyData { DataDate = DateTime.Today, MinTemperature = 12, MaxTemperature = 35} ); } Serializer.Serialize<T>不存在而拒绝编译。

我很乐意提供帮助,但就我所知,没有任何问题。

我接下来建议的事情:

  • 显示此异常中发生的事件的完整堆栈跟踪,包括任何内部异常(请参阅下面的修复)
  • 请检查完全您在594 zip中引用的文件(请查看“我需要什么文件.txt”,但我猜对你来说是正确的“Full / net30 / ...“; nuget包自动配置最合适的文件)
  • 请显示一个完全可重现的示例,即我可以按 F5 并查看确切的异常(我必须更改示例中的代码才能编译,这意味着我不再测试同样的事情)

修复正确的异常包装:

Serializer.Deserialize<T>