6

タイプ T のオブジェクトを取得し、それを XML としてシリアライズしてからファイルシステムに保存する Generic クラスがあります。ただし現在、オブジェクトがシリアライズ可能でない場合、シリアライズ操作は失敗します。それ自体は問題ではありませんが、クラス コンストラクターで T のインスタンスがシリアル化可能かどうかを確認し、そうでない場合は、後でではなくその時点でエラーをスローする方がよいと思います。

T のインスタンスを単純にインスタンス化して TRY...CATCH でシリアル化する以外に、XML としてシリアル化できることを確認する方法はありますか? なんらかの方法でクラス T を調べて、XML としてシリアライズできるかどうかを調べることができればよいのですが。

それが役立つ場合、コードはここで見ることができます: http://winrtstoragehelper.codeplex.com/SourceControl/changeset/view/ac24e6e923cd#WinRtUtility%2fWinRtUtility%2fObjectStorageHelper.cs

このコードは WinRT に対してコンパイルされることに注意してください (つまり、Windows 8 アプリで使用するためのものです) が、質問は C# の方言に関連していると思います。

前もって感謝します

ジェイミー

4

2 に答える 2

4

私の知る限り、さまざまな属性(SerializableDataContract)をチェックしたり、Type.IsSerializable(属性の存在をチェックするための便利な方法だと思います)をチェックしたとしても、実装が実際シリアライズ可能Serializableであることは保証されません。(編集:前述のように、質問で提供されているサンプルコードに見られるように、属性の装飾に依存しません。したがって、これらのフラグをチェックしても意味がありません。)XmlSerializerSerializable

私の経験では、アプリケーションで使用されているさまざまな型を検証する単体テストを使用し、try/catch を使用して成功/失敗するかどうかを確認することをお勧めします。実行時に、(毎回事前チェックするのではなく) try/catch を使用し、例外をログに記録/処理します。

単体テストの結果として有効な互換性のある型のリストがある場合は、以前のTテストで決定したコンパイル時のリストに対して事前チェックを行い、他の型はまったく役に立たないと想定できます。既知の有効な型のサブクラスを監視したい場合がありますが、有効なシリアル化可能な型から継承したとしても、それらの実装はそうではない可能性があります。

編集: これは Windows Phone 8 用であるため、そのプラットフォームの経験はありませんが、Silverlight を使用しました。その場合、オブジェクトがマークされていなくてもシリアル化できます[Serializable](実際、Silverlight には存在しません)。ビルトインXmlSerializerは、装飾に関係なく、すべてのパブリック プロパティに対して機能します。シリアル化可能かどうかを確認する唯一の方法は、シリアル化を試みて失敗を試行/キャッチするか、各プロパティを (および子オブジェクトを介して再帰的に) 検査し、各型をシリアル化できるかどうかを確認するアルゴリズムを作成することです。

EDITx2: あなたObjectStorageHelperの を見て、単純にシリアル化を試みて、失敗をキャッチすることをお勧めします。必ずしも例外を直接バブルアップする必要はありません。独自のカスタム例外でラップするか、シリアライゼーションの成功/失敗と失敗した理由を API コンシューマーに通知する結果オブジェクトを返すことができます。毎回高価なチェックを行うよりも、呼び出し元が有効なオブジェクトを使用していると想定することをお勧めします。

EDITx3: save メソッドで他の多くの作業を行っているため、コードを次のように書き直すことをお勧めします。

public async Task SaveAsync(T Obj)
{
    if (Obj == null)
        throw new ArgumentNullException("Obj");

    StorageFile file = null;
    StorageFolder folder = GetFolder(storageType);
    file = await folder.CreateFileAsync(FileName(Obj), CreationCollisionOption.ReplaceExisting);

    IRandomAccessStream writeStream = await file.OpenAsync(FileAccessMode.ReadWrite);
    using (Stream outStream = Task.Run(() => writeStream.AsStreamForWrite()).Result)
    {
        try
        {
            serializer.Serialize(outStream, Obj);
        }
        catch (InvalidOperationException ex)
        {
            throw new TypeNotSerializableException(typeof(T), ex);
        }

        await outStream.FlushAsync();
    }
}

このようにして、シリアライゼーションの問題を具体的に把握し、無効な/シリアライズ不可能なオブジェクトを提供したことを API コンシューマーに非常に明確に報告できます。このようにして、I/O 部分の一部として例外がスローされた場合、問題がどこにあるかがより明確になります。実際、シリアライゼーション/デシリアライゼーションの側面を独自の個別のメソッド/クラスに分離して、他のシリアライザーをフィードできるようにすることもできます (または、スタック トレースから問題をより明確にするか、単にメソッドに 1 つを実行させることができます)。しかし、これ以上のリライト/リファクタリングは、実際にはコードレビューに残され、目前の質問にはあまり有効ではありません.

参考までに、ユーザーが null を渡した場合、実際には何も起こらなかったときに保存が成功したと見なし、値が後で読み込まれないときに値が利用可能であると期待する可能性があるため、入力オブジェクトにも null チェックを入れました。あるnull を有効な値として許可する場合は、チェックでエラーがスローされることを気にしないでください。

于 2012-09-04T20:06:42.977 に答える
2

「シリアル化できる」とはどういう意味かによります。どのクラスも。でシリアル化できますXmlSerializer。シリアル化できるということは、エラーが発生しないということである場合は、例外をキャッチして確実に伝える必要があります。

于 2012-09-04T20:13:22.357 に答える