2011-12-20 14 views
4

私はこれを知っている必要がありますように感じるが、いくつかの理由のために....防止シリアライズ

ことなく、(おそらく抽象的)基本クラスから派生するクラスをシリアル化するための好ましい方法は何ですかすべての方法でツリーをシリアル化する?たとえば、派生しているクラスを制御することはできませんが、オブジェクトを複製するためにシリアライゼーションを使用したいと思うかもしれません。例えば

:SomeBaseClassは直列化可能としてマークされていないので、書かれたよう

// This is a base class that is outside my control, which derives from 
// some other base class that I know "nothing" about 
public abstract class SomeBaseClass : SomeOtherBaseClass 
{ 
    private string mBaseProperty = "Base Property"; 
    public string BaseProperty 
    { 
     get { return mBaseProperty; } 
     set { mBaseProperty = value; } 
    } 
} 

// This is the class that I do control 
[Serializable()] 
private class MyDerivedClass : SomeBassClass 
{ 
    // Assume normal constructors, etc. 

    // Here are some properties 
    private string mDerivedPropertyOne = String.Empty; 
    private string DerivedPropertyOne 
    { 
     get { return mDerivedPropertyOne ; } 
     set { mDerivedPropertyOne = value; } 
    } 

    private string mDerivedPropertyTwo = String.Empty; 
    private string DerivedPropertyTwo 
    { 
     get { return mDerivedPropertyTwo ; } 
     set { mDerivedPropertyTwo = value; } 
    } 

    // And now a quick-n-dirty Equals override 
     public override bool Equals(object obj) 
     { 
      if (obj == null) 
       return false; 

      MyDerivedClass compareTo = obj as MyDerivedClass; 
      if (compareTo == null) 
       return false; 

      return ((String.Compare(this.DerivedPropertyOne, 
            compareTo.DerivedPropertyOne, true) == 0) && 
        (String.Compare(this.DerivedPropertyTwo, 
            compareTo.DerivedPropertyTwo, true) == 0) && 
     } 
} 

// And while we're at it, here's a simple clone found elsewhere on StackOverflow 
public static class ObjectClone 
{ 
    public static T Clone<T>(this T source) 
    { 
     if (!typeof(T).IsSerializable) 
     {    
      throw new ArgumentException("The type must be serializable.", "source");   
     }   

     // Don't serialize a null object, simply return the default for that object   
     if (Object.ReferenceEquals(source, null)) 
     {    
      return default(T);   
     }   

     IFormatter formatter = new BinaryFormatter();   
     Stream stream = new MemoryStream();   
     using (stream)   
     {    
      formatter.Serialize(stream, source); 
      stream.Seek(0, SeekOrigin.Begin);    
      return (T)formatter.Deserialize(stream);   
     }   
    } 
} 

、これはSerializationExceptionをスローします。

+0

でXMLRootは(「MyDerivedClass」)属性を使用することができます。代わりのシリアライザを使用できますか? –

+0

これは基本クラスの内部を知らない限り、本質的に危険な操作です。基本クラスの作成者の意図がそのクラスのオブジェクトをシリアル化しない場合は、オブジェクトがデシリアライズ後に有効または有効な状態になるという保証はありません。派生オブジェクトのみのクローンについて話すことはあまり意味がありません。継承とは、派生クラスのすべてのインスタンスも、基本クラスの有効なインスタンスでなければならないことを意味します。 –

+0

MarcGravell、@JonasH、et。 al。これは私がよく受け継いだコードで遊んだ結果、より「学問的な」問題です。私はあなたのコメントに確かに同意します。 –

答えて

9

短い答え:継承を使用しない構成を使用します。シリアライズするメンバーを別のクラスに抽出し、シリアライズ可能なメンバーにします。これにより、ライフサイクルおよびシリアライゼーションの範囲にわたって必要とする制御が得られます。

一般に、シリアライズされたオブジェクトがダムデータホルダーになり、追加のロジックがラップされて追加されるのは良いパターンです。これは、protobuf、thrift、avroのような近代的な直列化フレームワークによって強化されています。これは、これらの直列化されたオブジェクトの背後にあるコードを生成し、継承を介してクラスの内部をぶち壊さないと期待します。

+0

それはダムと聞こえる。私はクラスBをAから継承しています(私が使用するフレームワークの設計によって)。私はBをシリアル化する必要がありますが、A.ではできません。BSerializedFieldsからBを継承する方法はありません。これは、複数の継承を必要とするためです。 'BSerializedFields'をBのフィールド' Data'として集計することができましたが、そのフィールドには 'obj.Data.FieldName'としてアクセスする必要がありました。私はB上に 'Data'にアクセスするためのいくつかのミューテータを作成することができましたが、それは多くのコードを必要とします。私はそのコードを生成することができました。しかし、ちょっと、私のシリアライザを実装するのはすでに簡単です。 –

+0

C#で書かれていないシリアル化ルーチンがありますが、それは良いパターンではありません。 –

0

あなたがにBinaryFormatterを使用している場合、それは*定義によって*種類についてうるさいです、とすべてをシリアライズしたいと思うでしょう、あなたの... BaseClassの