1

このクラスを考えてみましょう:

[Persistable]
public sealed class FileMoveTask : TaskBase
{
     [PersistMember]
     public string SourceFilePath { get; private set;}

     [PersistMember]
     public string DestFilePath { get; private set;}

     public FileMoveTask(string srcpath, string dstpath)
     {
         this.SourceFilePath = srcpath;
         this.DestFilePath = dstpath;

         //possibly other IMPORTANT initializations
     }

     //code
}

すべてのメンバーを attribute でシリアル化することにより、このクラスのオブジェクトを永続化できますPersistMember。しかし、逆シリアル化プロセス中にいくつかの問題 (設計上の問題) に直面しています。特に、問題はコンストラクターに存在する可能性のある「おそらく他の重要な初期化」にあり、プログラマーは、おそらくそれが意味をなさないために、少数のメンバーを永続化しない (つまり、メンバーに追加しない)ことを決定する場合があります。PersistMember

このような状況では、オブジェクトを元の状態とまったく同じ状態に逆シリアル化するにはどうすればよいでしょうか? この質問は、要約すると次のようになると思います。以前に渡されたのと同じ引数を渡して、デフォルト以外のコンストラクターを呼び出すにはどうすればよいでしょうか。それを行う方法はありますか?コンパイラによって強制できるルールをいくつか作成できますか (一種のメタプログラミング)? コンストラクター属性はここで役立ちますか?

4

2 に答える 2

4

この問題を解決する最も簡単な方法は、既存のよく知られた手法を使用することです。たとえば、.NET Frameworkで使用されている他のシリアル化メカニズムを見てください(そして、その巨大な多様性に気付くでしょう)。

たとえば、BinaryFormatterでは、SoapFormatterDataContractSerializerは、オブジェクトを逆シリアル化するために次の手法を使用します。

  1. FormatterServices.GetUnitializedObjectを呼び出して「生の」オブジェクトを取得する
  2. 構築されたオブジェクトに対して個別の事前シリアル化メソッドを呼び出します(OnSerializingAttributeでマークされたメソッドをチェックすることにより)。
  3. オブジェクトの状態を逆シリアル化します(適切な属性をチェックして、シリアライザーがスキップする必要のあるフィールドと、逆シリアル化する必要のあるフィールドを理解します)。
  4. デシリアライズされたオブジェクトでポストシリアライズメソッドを呼び出します(OnSerializedAttributeでマークされたメソッドをチェックします)。

一方、XmlSerializerは、まったく異なるアルゴリズムを使用します。「事前シリアル化」および「事後シリアル化」ステップとして使用する必要があるパラメーターなしのコンストラクターが必要です。

だから私のポイントは、それはシリアライザーのタイプとその実装にのみ依存するということです。そして、それでも、シリアライザーの作成者とシリアライザーの消費者の両方からの精神的な努力が必要です。

したがって、既存の手法の1つを使用することを強くお勧めしますが、ホイールを発明することはしません(オブジェクトの状態を復元するために他のカスタム属性を追加するなど)。既存の属性を使用して、.NETシリアル化機能からカスタムシリアル化メカニズムへの移行を簡素化することもできます(また、NonSerializableAttrubiteなどの追加の属性を使用することもできます)。

于 2012-11-26T11:36:03.713 に答える
1

これは 2 つの方法で解決できます。構成よりも規則を使用します (コンストラクター パラメーターをプロパティとして指定し、既定のコンストラクターを含めません)。

[Persistable]
public sealed class FileMoveTask : TaskBase
{
     [PersistMember]
     public string SourceFilePath { get; private set;}

     [PersistMember]
     public string DestFilePath { get; private set;}

     public FileMoveTask(string sourceFilePath, string destFilePath)
     {
         this.SourceFilePath = srcpath;
         this.DestFilePath = dstpath;

         //possibly other IMPORTANT initializations
     }

     //code
}

コンストラクターの引数に属性を明示的にタグ付けし、タグ付けされたコンストラクターを検索します。

[Persistable]
public sealed class FileMoveTask : TaskBase
{
     [PersistMember]
     public string SourceFilePath { get; private set;}

     [PersistMember]
     public string DestFilePath { get; private set;}

     public FileMoveTask([PersistMember("SourceFilePath")]string srcpath, [PersistMember("DestFilePath")]string dstpath)
     {
         this.SourceFilePath = srcpath;
         this.DestFilePath = dstpath;

         //possibly other IMPORTANT initializations
     }

     //code
}

属性または引数名は、設定するプロパティを知るために使用されるのではなく、コンストラクターを呼び出すときに使用するシリアル化データからの情報を知るために使用されます。

于 2012-11-26T10:12:40.170 に答える