【问题标题】:Deserializing TimeZoneInfo on Linux throws `The Month parameter must be in the range 1 through 12`在 Linux 上反序列化 TimeZoneInfo 会抛出“Month 参数必须在 1 到 12 的范围内”
【发布时间】:2019-12-30 12:01:40
【问题描述】:

我正在将一个库从 .net framework 4.7 迁移到 .net core 2.2,并发现 deep object cloning 存在问题,我将其缩小为下面的简短可重现代码 sn-p。

自己试试吧:

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace Test
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // any zone here, don't care what it is
            var zone = TimeZoneInfo.GetSystemTimeZones()[0];            
            var formatter = new BinaryFormatter();

            using (MemoryStream stream = new MemoryStream())
            {
                formatter.Serialize(stream, zone);
                stream.Seek(0, SeekOrigin.Begin);
                var result = formatter.Deserialize(stream);
                Console.WriteLine("all ok");
            }
        }
    }
}

在使用 .net core 2.2 的 Windows 平台上,这可以正常工作,但在 Linux 平台上出现异常:

Unhandled Exception: System.Runtime.Serialization.SerializationException: An error occurred while deserializing the object.  The serialized data is corrupt. ---> System.ArgumentOutOfRangeException: The Month parameter must be in the range 1 through 12.
Parameter name: month
   at System.TimeZoneInfo.TransitionTime.ValidateTransitionTime(DateTime timeOfDay, Int32 month, Int32 week, Int32 day, DayOfWeek dayOfWeek)
   at System.TimeZoneInfo.TransitionTime.System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(Object sender)
   --- End of inner exception stack trace ---
   at System.TimeZoneInfo.TransitionTime.System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(Object sender)
   at System.Runtime.Serialization.ObjectManager.RaiseDeserializationEvent()
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(BinaryParser serParser, Boolean fCheck)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, Boolean check)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
   at Test.Program.Main(String[] args)

问题:如何在 Linux 的 .net core 2.2 中使用带有 TimeZoneInfo 的二进制序列化?

【问题讨论】:

  • 当我尝试它时,它适用于 .Net Core 2.1(我没有安装 2.2)。它在 2.1 中对你有用吗?
  • 刚刚尝试过,它适用于我的 .Net Core 2.2...
  • @MatthewWatson - 这在基于 Linux 的环境中是否适合您?正如 OP 发布的那样,它可以在 Windows 上正常工作,但不适用于基于 Linux 的系统
  • 你尝试过干净的构建吗?升级后可能无法重建代码。检查项目 bin 文件夹中可执行文件的日期时间(发布和调试)。
  • 对于任何感兴趣的人,我已将此问题报告给 .net core repo github.com/dotnet/core/issues/3254

标签: c# .net serialization .net-core timezone


【解决方案1】:

确实,这似乎是一个错误。感谢您提出the issue

但是,从您的 cmets 看来,似乎有一个简单的解决方法。不要序列化TimeZoneInfo,而是更改您的对象以仅序列化ID。如果您愿意,可以在其周围放置一个带有 get/set 访问器的属性。

例如,而不是:

public class Foo
{
    public TimeZoneInfo TimeZone { get; set; }
}

你可以这样做:

public class Foo
{
    public string TimeZoneId { get; set; }

    public TimeZoneInfo TimeZone
    {
        get => TimeZoneInfo.FindSystemTimeZoneById(TimeZoneId);
        set => TimeZoneId = value.Id;
    }
}

BinaryFormatter 只对字段进行序列化,因此只有隐藏在 TimeZoneId 自动属性后面的字符串才会被序列化/反序列化。 TimeZoneInfo 在序列化/反序列化期间将被忽略,仅在您自己的代码中访问对象时使用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-02-22
    • 2016-12-21
    • 2018-08-31
    • 2023-02-11
    • 2018-02-28
    • 2012-07-20
    • 2020-06-24
    • 2021-01-08
    相关资源
    最近更新 更多