4

私に与えられた奇妙なタスクは、XML シリアライゼーションを使用して LARGE オブジェクトをシリアライズすることです。このオブジェクトには、複数のネストされた UserDefined クラスが含まれており、複数の DateTime フィールドがあります。DateTime データの要件は、最初にデータを作成および設定したユーザーの TimeZone で常に表示される必要があることです。したがって、逆シリアル化すると元の時刻と同じにならないため、UTC OR ローカル時刻は使用できません。また、値を UTC で表示することもできません。ローカル時間で表示する必要があります。私が必要としているのは、「絶対現地時間」の概念を表す奇妙なシリアル化形式です...それは「TimeZoneのない現地時間」になります。

正規表現を使用して、日付文字列から TZ を取り除くことができます。これは簡単です。しかし、私が扱っているオブジェクトのサイズが非常に大きいため、OutOfMemoryException が頻繁に発生します。一度デバッグなしで実行するのを見たところ、操作中に使用メモリが 100k から 800k に急増しました。よくない。そして、それはより小さなファイルの1つでした。

Doc.DocumentElement.InnerXML = Regex.Replace(Doc.DocumentElement.InnerXML, "(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2})(\\+|-)(\\d{2}:\\d{2})", "$1")

これまでのところ、私が見た唯一のオプションは、すべての dateTime フィールドの複製を作成し、DT フィールド自体を "XmlIgnore()" として設定し、ドキュメントが再ロードされた後にシリアル化された文字列データからすべての日付を手動で復元することです. これも実用的ではありません。カスタムの DateTime XML シリアル化を参照してください。

TimeZone データなしで DateTime オブジェクトをシリアル化するようにシリアル化エンジンを強制する方法はありますか? オブジェクト内のすべての DT プロパティに個別に適用する必要のない一般的なものが望ましいですか?

!!編集!!

部分的な解決策を見つけたかもしれません。少なくとも前進するのに役立つかもしれません。DateTimeKind.Unspecified をシリアル化すると、TimeZone データが添付されていないようです。これが私が探している解決策ですか。DateTime.SpecifyKind を使用してすべての DateTime データを強制的にキャストしますか?

public DateTime? StartDate
    {
        get 
        { return _StartDate; }
        set
        {
            if (_StartDate == value)
                return;

            if (value != null)
                _StartDate = DateTime.SpecifyKind(value.Value, DateTimeKind.Unspecified);
            else
                _StartDate = value;

            OnPropertyChanged("StartDate");
        }
    }
4

3 に答える 3

3

要件や前提を再評価する必要があると思います。

あなたが書いた:

DateTime データの要件は、最初にデータを作成および設定したユーザーの TimeZone で常に表示される必要があることです。したがって、逆シリアル化すると元と同じにはならないため、UTC OR ローカル時間を使用できません。

あなたの分析は正しくないと思います。ストレージへのシリアル化とユーザーへの「表示」を不必要に混在させているようです。しかし、これら 2 つのことは関連していてはなりません。私が理解している要件は次のとおりです。

  • 多数の異なる時間値をシリアライズおよびデシリアライズしたいと考えています。
  • それらの時間を「表示」するときは、表示で元のタイムゾーンを使用する必要があります。

これらは別個の要件です。

DateTime をシリアル化すると、ある時点が保存されますが、TimeZone 情報は失われます。XMLドキュメントごとに1回、タイムゾーン情報を個別にシリアル化する必要があるようです。これを行うと、時間の逆シリアル化が自動的に機能します。最初にストレージに入れていたストレージから正確な瞬間を常に取得します。

時刻を表示するときは、XML ドキュメントに別途格納されているタイムゾーン情報を使用します。TimeZone を含むプロパティが元のオブジェクトに存在しない場合、オブジェクト モデルがアプリケーションの要件に適していないように思われます。その場合、オブジェクト定義を変更して、オブジェクトを識別する文字列を含める必要があります。タイムゾーン。( http://msdn.microsoft.com/en-us/library/system.timezoneinfo.aspxを参照)

メモリ不足エラーに関しては、それは無関係の問題である可能性があります。また、大きな XmlDocument オブジェクトを操作していることが原因である可能性もあります。Xml シリアライゼーションを使用する場合、これは不要なはずです。

于 2012-04-25T23:38:39.700 に答える
0

そのような日付を保持するカスタム型を作成することをお勧めします。これにより、任意の方法でシリアル化を処理できます。より簡単な方法として、この場合に正確に指定されているタイムゾーンなしで ISO8601 形式 (2012-05-04-26T12:57) の文字列として保存することを検討してください。

実際に絶対時間を節約する必要があるとすぐに興味深い問題が発生するため、シリアル化されたデータからタイムゾーンを大規模に削除することはお勧めできません。特にコードが共有されている場合。

于 2012-04-26T19:49:34.210 に答える
0

答えが見つかりました。これはまさに私が探していたものではありませんが、効果的な回避策として役立ちます。

private static readonly Regex DTCheck = new Regex(@"(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})([\+|-]\d{2}:\d{2})");

    /// <summary>
    /// Removes any instances of the TimeZoneOffset from the RigX after it has been serialized into an XMLString ++ Called from the "Save" process
    /// </summary>
    /// <param name="rigx"></param>
    /// <returns>StringReader referencing the re-formatted XML String</returns>
    private static StringReader RemoveTZOffsetFromRigX(RigX rigx)
    {
        StringBuilder sb = new StringBuilder();
        StringWriter sw = new StringWriter(sb);
        XmlSerializer ser = new XmlSerializer(typeof(RigX));

        ser.Serialize(sw, rigx);

        string xmlText = sb.ToString();

        if (DTCheck.IsMatch(xmlText))
            xmlText = DTCheck.Replace(xmlText, "$1");

        StringReader Sreader = new StringReader(xmlText);

        return Sreader;
    }

    /// <summary>
    /// Removes the TimeZone offset from a RigX as referenced by stream.  Returns a reader linked to the new stream  ++ Called from the "Load" process
    /// </summary>
    /// <param name="stream">stream containing the initial RigX XML String</param>
    /// <returns>StringReader referencing the re-formatted XML String</returns>
    private StringReader RemoveTZOffsetFromXML(MemoryStream stream)
    {
        stream.Position = 0;
        StreamReader reader = new StreamReader(stream, Encoding.UTF8);

        string xmlText = reader.ReadToEnd();
        reader.Close();
        stream.Close();

        if (DTCheck.IsMatch(xmlText))
            xmlText = DTCheck.Replace(xmlText, "$1");

        StringReader Sreader = new StringReader(xmlText);

        return Sreader;
    }

ファイルから XML を読み取った後、シリアライザーを介して実行する前に、生の XML テキストに対して正規表現を実行してオフセットを削除します。この関数は、変更された XML 文字列に対して実行される文字列リーダーを返します。これは、オブジェクトへの逆シリアル化を通じて実行できます。

シリアライザーを使用して xml を出力ストリームに直接保存するのではなく、stringBuilder を使用してシリアライズされた xml をインターセプトできます。次に、読み込み手順と同じプロセスを使用して、RegularExpression を介して TimeZone オフセットを削除し、変更されたテキストにリンクされた StringReader を返します。これを使用して、データをファイルに書き戻します。

少しハックな感じですが、効果的です。ただし、非常にメモリを集中的に使用します。可能であれば関数を直接デバッグしないでください。または、必要に応じて、文字列を評価しないようにしてください。前回、VS インスタンスを完全にクラッシュさせました。

于 2012-04-27T19:45:16.653 に答える