2010-12-28 46 views
12

次のメソッドを使用してオブジェクトのディープクローンを作成しようとしています。DataContract属性と.netのSerializable属性の違い

public static T DeepClone<T>(this T target) 
    { 
     using (MemoryStream stream = new MemoryStream()) 
     { 
      BinaryFormatter formatter = new BinaryFormatter(); 
      formatter.Serialize(stream, target); 
      stream.Position = 0; 
      return (T)formatter.Deserialize(stream); 
     } 
    } 

このメソッドには、シリアライズされたオブジェクト、つまり「シリアライズ可能」という属性を持つクラスのオブジェクトが必要です。私はそれに属性 "DataContract"を持っているクラスを持っていますが、メソッドはこの属性で動作していません。私は "DataContract"もシリアライザの一種だと思うが、おそらく "シリアライザブル"のそれとは異なる。

誰にでも2つの違いを教えてください。また、 "DataContract"属性と "Serializable"属性の両方の作業を行う属性が1つだけのオブジェクトのディープクローンを作成することが可能かどうか、あるいは恐らくディープクローンを作成する別の方法を教えてください。

助けてください!

答えて

23

Serializableは、BinaryFormatterが動作するために必要です。

DataContractおよびDataMember属性は、DataContractSerializerで使用されます。

両方のシリアライザの属性を使用してクラスを修飾することができます。

+0

応答@Odedをありがとう。ここでは1つの質問だけ。このクラスはWCFサービスで使用されています。サービスのサービスリファレンスを追加して、私の消費者プロジェクトでこのサービスを利用しています。サービスに変更があるたびに、サービス参照を更新する必要があります。両方の属性を使用してサービスを更新すると、.netはService ReferenceのReference.csクラスに同じ名前の2つのプロパティを作成します。 1つは "DataMember"と "Serializable"属性です。これによりビルドエラーが発生します。これを回避する方法はありますか? – samar

+0

@samar - 私が知る限り、 'DataContract'が使われると' Serializable'は無視されます。私はあなたが持っている問題について聞いたことがありません。 – Oded

5

DataContractはWCF、したがって.NET 3.0以降で使用されます。 .net 2.0以下では、DataContract、DataMember属性はなく、Serializableのみです。

Odedと書かれているように、BinaryFormatterを使用する場合は、タイプをSerializableで飾る必要があります。

2

オブジェクト構造にReflectionを使用して検査を行い、デシリアライズに必要なアセンブリをすべて見つけ出し、ブートストラップのためにそれらを直列化しました。

少しの作業で、深いコピーのための同様の方法を構築できます。基本的には、循環参照を検出するためのディクショナリを実行する再帰的メソッドが必要です。それはあなたが各フィールドの値の(偶数の参照をコピーせずに)最も最も浅いコピーを作成するためにSystem.Runtime.Serialization.FormatterServices.GetUninitializedObject(Type type)のような出力オブジェクトと何かを追加する必要が取り組んで取得するには

private void InspectRecursively(object input, 
    Dictionary<object, bool> processedObjects) 
{ 
    if ((input != null) && !processedObjects.ContainsKey(input)) 
    { 
    processedObjects.Add(input, true); 

    List<FieldInfo> fields = type.GetFields(BindingFlags.Instance | 
     BindingFlags.Public | BindingFlags.NonPublic); 
    foreach (FieldInfo field in fields) 
    { 
     object nextInput = field.GetValue(input); 

     if (nextInput is System.Collections.IEnumerable) 
     { 
     System.Collections.IEnumerator enumerator = (nextInput as 
      System.Collections.IEnumerable).GetEnumerator(); 

     while (enumerator.MoveNext()) 
     { 
      InspectRecursively(enumerator.Current, processedObjects); 
     } 
     } 
     else 
     { 
     InspectRecursively(nextInput, processedObjects); 
     } 
    } 
    } 
} 

:メソッド内には、このようなに関するすべてのフィールドを検査します。最後に、しかし、この実装は_あまりにも、デシリアライズによって_supported アンで登録されたイベントハンドラを、サポートしていませんfield.SetValue(input, output)

ようなもので、各フィールドを設定することができます。さらに、階層の各オブジェクトは、そのクラスのコンストラクタが何かを初期化する必要があり、すべてのフィールドを設定する必要がある場合、壊れてしまいます。最後の点は、クラスがそれぞれの実装を持っている場合のみ、直列化でのみ機能します。方法[OnDeserialized]と表示され、ISerializable、...を実装します。

関連する問題