1

DataContract を介してシングルトンをシリアル化および逆シリアル化する際に問題があります。

最初のいくつかの事実:

1.) Singleton is "internal"
2.) Singleton contains Dictionaries

シリアライゼーションとデシリアライゼーションは正常に機能しますが、シングルトンの正しい方法ではありません。xml を逆シリアル化すると、常にシングルトンの新しいインスタンスが生成され、シングルトン オブジェクトの現在の参照が上書きされますが、その後はシングルトンではなくなります。

誰にもアイデアはありますか?- ありがとう。

4

5 に答える 5

0

(.net 4.0 のコード)

私は同じ問題を抱えていました:デシリアライゼーションはシングルトンクラスの新しいインスタンスを作成する必要があります.メンバー関数の内部にあるため(!)できます:コンストラクターはメンバーに表示されますが、そのインスタンスはシングルトンインスタンスを置き換えることはできません外から見える(「これ」)。

したがって、デシリアライズされたインスタンスから「this」インスタンスにプロパティをコピーする必要があります。

手作業でコピーを行うとすぐに古くなってしまうので、リフレクションを使用して、[xmlignore] とマークされていないパブリックの書き込み可能なメンバーをコピーする私のソリューションを次に示します。

    public static class SerializationHelpers
    {

      /// <summary>
      /// Copy all public props and fields that are not xmlignore
      /// </summary>
      /// <typeparam name="T"></typeparam>
      /// <param name="target"></param>
      /// <param name="other"></param>
      public static void CopyTypeFields<T>(T target, T other)
      {

        // get all public static properties of MyClass type
        PropertyInfo[] propertyInfos = other.GetType().GetProperties(BindingFlags.Public  

        | BindingFlags.Instance);
        FieldInfo[] fis = other.GetType().GetFields(BindingFlags.Public | 
        BindingFlags.Instance);


        foreach (FieldInfo fi in fis)
        {
          if ((fi.Attributes & FieldAttributes.FieldAccessMask) != 
              FieldAttributes.Literal &&
              (fi.Attributes & FieldAttributes.FieldAccessMask) != 
              FieldAttributes.Static)
          {
            if (IsXmlIgnored(fi)) { continue; }
            var myval = fi.GetValue(other);
            fi.SetValue(target, myval);
          }
        }


        foreach (PropertyInfo pi in propertyInfos)
        {
          if (!pi.CanWrite || !pi.CanRead) { continue; }
          if (IsXmlIgnored(pi)) { continue; }

          var myval = pi.GetValue(other, null);
          pi.SetValue(target, myval, null);
        }
      }

      private static bool IsXmlIgnored(MemberInfo pi)
      {
        object[] fiGetCustomAttributes = pi.GetCustomAttributes(false);
        foreach (object ob in fiGetCustomAttributes)
        {
          if (ob.GetType().
              Equals(typeof(System.Xml.Serialization.XmlIgnoreAttribute)))
          {
            return true;
          }
        }
        return false;
      }

    }

    // to use it ...
    // the deserialization method of the singleton mySingleton



    public bool loadSingleton()
    {
      bool ret= false;

      try
      {
        Type myType = GetType();
        XmlSerializer reader = new XmlSerializer(myType);
        try
        {
          using (StreamReader file = new StreamReader(filename))
          {
            try
            {
              mySingleton t1 = (mySingleton)reader.Deserialize(file);
              CopySerializationFields(t1);
              ret= true;
            }

            catch
            {
              ...
            }
          }
        }
        catch
        {
          ...
        }
      }
      catch (Exception ex)
      {
        ...
      }
      return ret;
    }


    private void CopySerializationFields(ProcessingSettings other)
    {
      SerializationHelpers.CopyTypeFields(this, other);
    }
于 2012-12-20T16:54:17.800 に答える
0

アトミック クラスの同様の解決策をかなり長く検索したところ、Marc Gravellによる同様の問題に対する回答が見つかりました。これはシングルトンでも機能します。

シングルトン クラスでは、インターフェイス System.Runtime.Serialization.IObjectReference によって定義された GetRealObject メソッドを実装します。必要に応じて、以前にシリアル化されたデータをシングルトンに追加し、逆シリアル化後に使用される参照として静的参照を返すこともできます。

これが私の例です:

[System.Runtime.Serialization.DataContract]
public class MySingletonClass : System.Runtime.Serialization.IObjectReference
{
    private MySingletonClass()
    {
    }

    private static MySingletonClass _Instance;
    public static MySingletonClass Instance
    {
        get
        {
            if (_Instance == null)
                _Instance = new MySingletonClass();
            return _Instance;
        }
    }

    object System.Runtime.Serialization.IObjectReference.GetRealObject(System.Runtime.Serialization.StreamingContext context)
    {
        MySingletonClass realObject = Instance;
        realObject.Merge(this);
        return realObject;
    }

    private void Merge(MySingletonClass otherInstance)
    {
        // do your merging here
    }
}

これは、アトミック クラスにも使用できます。Instance プロパティを GetInstance メソッドに変更し、GetRealObject メソッド (つまり ID) で適切なプロパティを指定して呼び出すだけです。

于 2015-01-08T15:13:35.137 に答える
0

NetDataContractSerializer を使用してみてください-

NetDataContractSerializer は、1 つの重要な点で DataContractSerializer と異なります。NetDataContractSerializer には、シリアル化された XML に CLR 型情報が含まれていますが、DataContractSerializer には含まれていません。したがって、NetDataContractSerializer は、シリアル化と逆シリアル化の両方の端が同じ CLR 型を共有している場合にのみ使用できます。

シリアライザーは、DataContractAttribute または SerializableAttribute 属性が適用された型をシリアル化できます。また、ISerializable を実装する型をシリアル化します。

コード例:

[DataContract(Name = "Customer", Namespace = "http://www.contoso.com")]
class Person : IExtensibleDataObject
{
    [DataMember()]
    public string FirstName;
    [DataMember]
    public string LastName;
    [DataMember()]
    public int ID;

    public Person(string newfName, string newLName, int newID)
    {
        FirstName = newfName;
        LastName = newLName;
        ID = newID;
    }

    private ExtensionDataObject extensionData_Value;    
    public ExtensionDataObject ExtensionData
    {
        get { return extensionData_Value; }
        set { extensionData_Value = value; }
    }
}

シリアル化:

Person p1 = new Person("Zighetti", "Barbara", 101);
FileStream fs = new FileStream(fileName, FileMode.Create);
XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(fs);
NetDataContractSerializer ser = new NetDataContractSerializer();
ser.WriteObject(writer, p1);

MSDNリンクはこちら

于 2012-07-24T15:46:49.180 に答える
0

msdn のこのリンクを確認してください。シングルトンのシリアル化の例があります。逆シリアル化の後、オブジェクトではなく参照を返す必要があります。

于 2012-07-24T14:52:55.420 に答える
0
[DataContract]
public sealed class SerializableSingletonPattern
{
    public static SerializableSingletonPattern Instance { get; private set; } = new SerializableSingletonPattern();
    [DataMember] public bool YourData { get; private set; }

    // explicit static constructor so C# compiler will not mark type as beforefieldinit
    static SerializableSingletonPattern() { }

    SerializableSingletonPattern() // your constructor
    {
    }

    [OnDeserialized]
    void OnDeserialized(StreamingContext context)
    {
        Instance = this;
    }
}
于 2021-02-17T10:49:42.023 に答える