Практическое руководство. Сохранение часовых поясов во внедренном ресурсе

Для приложения с поддержкой часового пояса часто требуется наличие определенного часового пояса. Тем не менее, поскольку доступность отдельных TimeZoneInfo объектов зависит от информации, хранящейся в реестре локальной системы, даже обычно доступные часовые пояса могут быть отсутствуют. Кроме того, сведения о пользовательских часовых поясах, созданных с помощью CreateCustomTimeZone метода, не хранятся с другими сведениями часового пояса в реестре. Чтобы обеспечить доступность этих часовых поясов при необходимости, их можно сохранить путем сериализации и последующего восстановления путем десериализации.

Как правило, сериализация TimeZoneInfo объекта происходит отдельно от приложения с поддержкой часового пояса. В зависимости от хранилища данных, используемого для хранения сериализованных TimeZoneInfo объектов, данные часового пояса могут быть сериализованы в рамках процедуры установки или установки (например, при хранении данных в разделе приложения реестра) или в рамках подпрограммы служебной программы, которая выполняется до компиляции окончательного приложения (например, при хранении сериализованных данных в файле XML-ресурса .NET (resx).

Помимо файла ресурсов, скомпилированного с помощью приложения, для сведений часового пояса можно использовать несколько других хранилищ данных. следующие основные параметры.

  • Реестр. Обратите внимание, что приложение должно использовать вложенные ключи собственного ключа приложения для хранения пользовательских данных часового пояса, а не с помощью подразделов HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zone.

  • Файлы конфигурации.

  • Другие системные файлы.

Сохранение часового пояса путем сериализации его в RESX-файл

  1. Получение существующего часового пояса или создание нового часового пояса.

    Сведения о получении существующего часового пояса см. в статье "Практическое руководство. Доступ к предопределенным объектам UTC и локальным часовым поясам" и " Практическое руководство. Создание экземпляра объекта TimeZoneInfo".

    Чтобы создать новый часовой пояс, вызовите одну из перегрузок CreateCustomTimeZone метода. Дополнительные сведения см. в разделе "Практическое руководство . Создание часовых поясов без правил корректировки и практическое руководство. Создание часовых поясов с правилами корректировки".

  2. ToSerializedString Вызовите метод для создания строки, содержащей данные часового пояса.

  3. Создайте StreamWriter экземпляр объекта, указав имя и при необходимости путь resx-файла к конструктору StreamWriter класса.

  4. Создайте ResXResourceWriter экземпляр объекта, передав StreamWriter объект конструктору ResXResourceWriter класса.

  5. Передайте сериализованную строку часового пояса в ResXResourceWriter.AddResource метод.

  6. Вызовите метод ResXResourceWriter.Generate .

  7. Вызовите метод ResXResourceWriter.Close .

  8. StreamWriter Закройте объект, вызвав его Close метод.

  9. Добавьте созданный RESX-файл в проект Visual Studio приложения.

  10. Используя окно свойств в Visual Studio, убедитесь, что для свойства действия сборки RESX-файла задано значение Embedded Resource.

Пример

В следующем примере сериализуется TimeZoneInfo объект, представляющий центральное стандартное время и TimeZoneInfo объект, представляющий станцию Палмера, время Антарктиды в XML-файл ресурса .NET, который называется SerializedTimeZones.resx. Центральное стандартное время обычно определяется в реестре; Палмер станции, Антарктида является пользовательским часовом поясом.

TimeZoneSerialization()
{
   TextWriter writeStream;
   Dictionary<string, string> resources = new Dictionary<string, string>();
   // Determine if .resx file exists
   if (File.Exists(resxName))
   {
      // Open reader
      TextReader readStream = new StreamReader(resxName);
      ResXResourceReader resReader = new ResXResourceReader(readStream);
      foreach (DictionaryEntry item in resReader)
      {
         if (! (((string) item.Key) == "CentralStandardTime" ||
                ((string) item.Key) == "PalmerStandardTime" ))
            resources.Add((string)item.Key, (string) item.Value);
      }
      readStream.Close();
      // Delete file, since write method creates duplicate xml headers
      File.Delete(resxName);
   }

   // Open stream to write to .resx file
   try
   {
      writeStream = new StreamWriter(resxName, true);
   }
   catch (FileNotFoundException e)
   {
      // Handle failure to find file
      Console.WriteLine("{0}: The file {1} could not be found.", e.GetType().Name, resxName);
      return;
   }

   // Get resource writer
   ResXResourceWriter resWriter = new ResXResourceWriter(writeStream);

   // Add resources from existing file
   foreach (KeyValuePair<string, string> item in resources)
   {
      resWriter.AddResource(item.Key, item.Value);
   }

   // Serialize Central Standard Time
   try
   {
      TimeZoneInfo cst = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
      resWriter.AddResource(cst.Id.Replace(" ", string.Empty), cst.ToSerializedString());
   }
   catch (TimeZoneNotFoundException)
   {
      Console.WriteLine("The Central Standard Time zone could not be found.");
   }

   // Create time zone for Palmer, Antarctica
   //
   // Define transition times to/from DST
   TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 4, 0, 0),
                                                                                              10, 2, DayOfWeek.Sunday);
   TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0),
                                                                                            3, 2, DayOfWeek.Sunday);
   // Define adjustment rule
   TimeSpan delta = new TimeSpan(1, 0, 0);
   TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1),
                                         DateTime.MaxValue.Date, delta, startTransition, endTransition);
   // Create array for adjustment rules
   TimeZoneInfo.AdjustmentRule[] adjustments = {adjustment};
   // Define other custom time zone arguments
   string DisplayName = "(GMT-04:00) Antarctica/Palmer Time";
   string standardName = "Palmer Standard Time";
   string daylightName = "Palmer Daylight Time";
   TimeSpan offset = new TimeSpan(-4, 0, 0);
   TimeZoneInfo palmer = TimeZoneInfo.CreateCustomTimeZone(standardName, offset, DisplayName, standardName, daylightName, adjustments);
   resWriter.AddResource(palmer.Id.Replace(" ", String.Empty), palmer.ToSerializedString());

   // Save changes to .resx file
   resWriter.Generate();
   resWriter.Close();
   writeStream.Close();
}
Private Sub SerializeTimeZones()
    Dim writeStream As TextWriter
    Dim resources As New Dictionary(Of String, String)
    ' Determine if .resx file exists
    If File.Exists(resxName) Then
        ' Open reader
        Dim readStream As TextReader = New StreamReader(resxName)
        Dim resReader As New ResXResourceReader(readStream)
        For Each item As DictionaryEntry In resReader
            If Not (CStr(item.Key) = "CentralStandardTime" Or _
                    CStr(item.Key) = "PalmerStandardTime") Then
                resources.Add(CStr(item.Key), CStr(item.Value))
            End If
        Next
        readStream.Close()
        ' Delete file, since write method creates duplicate xml headers
        File.Delete(resxName)
    End If

    ' Open stream to write to .resx file
    Try
        writeStream = New StreamWriter(resxName, True)
    Catch e As FileNotFoundException
        ' Handle failure to find file
        Console.WriteLine("{0}: The file {1} could not be found.", e.GetType().Name, resxName)
        Exit Sub
    End Try

    ' Get resource writer
    Dim resWriter As ResXResourceWriter = New ResXResourceWriter(writeStream)

    ' Add resources from existing file
    For Each item As KeyValuePair(Of String, String) In resources
        resWriter.AddResource(item.Key, item.Value)
    Next
    ' Serialize Central Standard Time
    Try
        Dim cst As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")
        resWriter.AddResource(cst.Id.Replace(" ", String.Empty), cst.ToSerializedString())
    Catch
        Console.WriteLine("The Central Standard Time zone could not be found.")
    End Try

    ' Create time zone for Palmer, Antarctica
    '
    ' Define transition times to/from DST
    Dim startTransition As TimeZoneInfo.TransitionTime = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#4:00:00 AM#, 10, 2, DayOfWeek.Sunday)
    Dim endTransition As TimeZoneInfo.TransitionTime = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#3:00:00 AM#, 3, 2, DayOfWeek.Sunday)
    ' Define adjustment rule
    Dim delta As TimeSpan = New TimeSpan(1, 0, 0)
    Dim adjustment As TimeZoneInfo.AdjustmentRule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#10/1/1999#, Date.MaxValue.Date, delta, startTransition, endTransition)
    ' Create array for adjustment rules
    Dim adjustments() As TimeZoneInfo.AdjustmentRule = {adjustment}
    ' Define other custom time zone arguments
    Dim DisplayName As String = "(GMT-04:00) Antarctica/Palmer Time"
    Dim standardName As String = "Palmer Standard Time"
    Dim daylightName As String = "Palmer Daylight Time"
    Dim offset As TimeSpan = New TimeSpan(-4, 0, 0)
    Dim palmer As TimeZoneInfo = TimeZoneInfo.CreateCustomTimeZone(standardName, offset, DisplayName, standardName, daylightName, adjustments)
    resWriter.AddResource(palmer.Id.Replace(" ", String.Empty), palmer.ToSerializedString())

    ' Save changes to .resx file 
    resWriter.Generate()
    resWriter.Close()
    writeStream.Close()
End Sub

В этом примере сериализуются TimeZoneInfo объекты, чтобы они были доступны в файле ресурсов во время компиляции.

Так как метод ResXResourceWriter.Generate добавляет полные сведения заголовка в ФАЙЛ ресурсов .NET XML, его нельзя использовать для добавления ресурсов в существующий файл. Этот пример обрабатывается путем проверка для файла SerializedTimeZones.resx и, если он существует, сохраняя все ресурсы, отличные от двух сериализованных часовых поясов, в универсальный Dictionary<TKey,TValue> объект. Затем существующий файл удаляется, а существующие ресурсы добавляются в новый файл SerializedTimeZones.resx. В этот файл также добавляются сериализованные данные часового пояса.

Поля ключей (или имени) ресурсов не должны содержать внедренные пробелы. Метод Replace(String, String) вызывается для удаления всех внедренных пробелов в идентификаторах часового пояса перед назначением файлу ресурса.

Компиляция кода

Для этого примера требуются:

  • Эта ссылка на System.Windows.Forms.dll и System.Core.dll будет добавлена в проект.

  • Импортируются следующие пространства имен:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;
    using System.Reflection;
    using System.Resources;
    using System.Windows.Forms;
    
    Imports System.Globalization
    Imports System.IO
    Imports System.Reflection
    Imports System.Resources
    

См. также