Cでの静的オブジェクトのシリアル化#

コンテキスト



多くの設定があるプロジェクトの1つで作業しているときに、この質問に答えました。 開発中に新しい設定の追加が行われたという事実を考慮すると、プログラムモジュールからアクセスできるクラスを作成する必要があることが明らかになりました。 このために、もちろん静的クラスが使用され、AppSettingsと呼ばれました。 もちろん、Properties.Settingsを使用することもできます...詳細は説明しませんが、このオプションは適合しませんでした。



問題の本質



クラスは静的であるため、通常のシリアル化は機能しません。 見てみましょう。 単純な静的クラスがあるとしましょう:

public static class TestStatic { // Fields... private static int _Counter; public static int Counter { get { return _Counter; } set { _Counter = value; } } }
      
      







一般に、クラスが静的でない場合は、System.Xml.Serialization.XmlSerializerを使用できます。 これは私たちの場合ではありません-静的クラスがあります。この場合、XmlSerializer.Serializeメソッドはクラス型ではなくクラスのインスタンスを必要とするため、コンパイラは 'Test1.TestStatic'は 'type'を生成しますが、変数 '。



解決策



少しグーグルで、わかりやすいものは見つかりませんでした。 私が見た唯一のことは、静的フィールドを持つクラスをシリアル化する方法でした。 私の脳では、反射だけが回っていました。 さて、いくつかの実験の後、次のクラスを作成しました。



 public static class SerializeStatic { public static bool Save(Type static_class, string filename) { try { FieldInfo[] fields = static_class.GetFields(BindingFlags.Static | BindingFlags.NonPublic); object[,] a = new object[fields.Length, 2]; int i = 0; foreach (FieldInfo field in fields) { a[i, 0] = field.Name; a[i, 1] = field.GetValue(null); i++; }; Stream f = File.Open(filename, FileMode.Create); SoapFormatter formatter = new SoapFormatter(); formatter.Serialize(f, a); f.Close(); return true; } catch { return false; } } public static bool Load(Type static_class, string filename) { try { FieldInfo[] fields = static_class.GetFields(BindingFlags.Static | BindingFlags.NonPublic); object[,] a; Stream f = File.Open(filename, FileMode.Open); SoapFormatter formatter = new SoapFormatter(); a = formatter.Deserialize(f) as object[,]; f.Close(); if (a.GetLength(0) != fields.Length) return false; int i = 0; foreach (FieldInfo field in fields) { if (field.Name == (a[i, 0] as string)) { if (a[i, 1] != null) field.SetValue(null, a[i, 1]); } i++; }; return true; } catch { return false; } } }
      
      







ポイントは簡単です:

  1. 静的フィールドを取得します。

    FieldInfo [] fields = static_class.GetFields(BindingFlags.Static | BindingFlags.NonPublic);

  2. マトリックスを作成し、フィールド名と値を入力します

  3. それでは、SoapFormaterを使用してファイルに書き込みます。





ファイルからのダウンロードも実行されます。 私の意見で唯一のことは注目に値します:クラスのフィールドの1つに別のクラスがある場合、この場合は2番目のクラスを[Serializable]として指定するだけで十分です。 つまり、TestStaticでそのような発表がある場合:



 public static BrowserSettings OperaSettings { get { return _OperaSettings; } set { _OperaSettings = value; } }
      
      





その後、BrowserSettingsクラスは次のようになります。

 [Serializable] public class BrowserSettings { //... }
      
      







使い方



保存するには、次を使用します。

 SerializeStatic.Save(typeof(TestStatic), "file.xml");
      
      







ダウンロードするには:

 if (!SerializeStatic.Load(typeof(AppSettings), "file.xml")) ;
      
      






All Articles