C# - Tetszőleges objektum konvertálása bináris állománnyá

forráskód letöltése
Ha egy Form-ra teszünk egy TextBox kontrolt, majd a Text property-jébe szöveget írunk, akkor ez az érték megmarad akkor is, ha a projektet bezárjuk és később újra megnyitjuk.
Sok esetben jó lenne hasonló adattárolás, de nem csak a kontroljainkhoz, hanem egyéb, tetszőleges osztályainkhoz. Még jobb lenne, ha ezek értéküket megőriznék akkor is, ha a program futási idejében történt változás bennük.
Szerencsére erre is van lehetőség: tetszőleges adattípusokat, tömböket, sőt akár egész osztályokat konvertálhatunk bináris formátumra és írhatjuk állományba, majd onnan egyszerűen visszatölthetjük, mondjuk a programunk újraindításakor.
Ebben a példában a következő lesz a feladatunk: létrehozunk egy osztályt két property-vel. Majd ebből az osztályból egy példányt, amelyet egy állományba írunk és visszaolvasunk annak ellenőrzésére, hogy az elmentett tartalom vissza is került-e a helyére.
Az új osztályhoz szükség lesz néhány speciális elemre is, hogy a fenti feladatot egyszerűen végrehajthassuk.
Az első ilyen, hogy az osztály létrehozásánál rögtön meg kell adnunk a Serializable attribútumot, valamint az, hogy az osztályba implementálnunk kell az ISerializable interfészt is.
  [Serializable()] 
  public class TestClass: ISerializable 
  {
    private int FA;
    private string FB;
Ezt követően létrehozzuk a két property-t, melynél semmi különös tennivalónk nincs a hagyományos esetekhez képest.
    public int A
    {
      get {return FA;}
      set {FA = value;}
    }
    public string B
    {
      get {return FB;}
      set {FB = value;}
    }
Létrehozzuk az osztály konstruktorát is, melyben alapértelmezett értékekkel látjuk el a két property-t.
    public TestClass()
    {
      FA = 100;
      FB = "Software Online";
    }
Az ISerializable interfész implementálása miatt szüksége lesz osztályunknak egy olyan konstruktorra is, mely az alábbiakban látható. Ennek kötött a paraméterlistája. Szerepe akkor lesz ennek a változatnak, mikor osztályunkból úgy hozunk létre példányt, hogy egy már binárissá alakított adathalmazt szeretnénk visszakonvertálni. Ekkor kerül meghívásra e konstruktor, ahol az info paraméter GetValue függvényének hívásával lekérdezhetjük az adott tulajdonság tárolt értékét.
    public TestClass(SerializationInfo info, StreamingContext context) 
    {
      FA = (int)info.GetValue("FA", typeof(int));
      FB = (string)info.GetValue("FB", typeof(string));
    }
Szintén az ISerializable interfész implementálása miatt egy GetObjectData függvényt is létre kell hoznunk. Ennek az adatok mentésében lesz szerepe. Meghívásakor az info paraméter AddValue függvényének felhasználásával képesek leszünk a tárolni kívánt adatokat átadni. Az AddValue függvény két paramétert vár: az elsőbe kell megadni az adatunk nevét, melyet tetszőlegesre választhatunk, másodikként pedig a tárolandó értéket.
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
      info.AddValue("FA", FA);
      info.AddValue("FB", FB);
    }  
  }
Ezen plusz lépések után az osztályunk már használható is. Próbaképpen hozzunk létre egy példányt és mentsük el egy x.dat bináris állományba. Ehhez szükségünk lesz egy FileStream osztályra, mely az állománykezelést végzi. A konvertáláshoz a BinaryFormatter osztály segít bennünket. Ennek Serialize függvénye végzi el a munka érdemi részét. Első paraméterként az állományt tartalmazó FileStream osztályt, míg másodikként a konvertálandó osztály példányát kell megadnunk. A Serialize függvény fogja az osztályunk GetObjectData függvényét meghívni.
    private void button1_Click(object sender, System.EventArgs e)
    {
      TestClass tc = new TestClass();
      tc.A = 123456;
      FileStream fs = File.Create("x.dat");
      BinaryFormatter bf = new BinaryFormatter();
      bf.Serialize(fs, tc);
      fs.Close();
    }
Ha adott az állomány, akkor lássuk, hogy lesz belőle ismét osztály. Szintén kell egy FileStream osztály, mellyel megnyitjuk a már létező állományt. Ezt követően szintén a BinaryFormatter osztály kerül felhasználásra, amelynek most a Deserialize függvényét hívjuk meg, paraméterként átadva a már létrehozott FileStream osztály példányát.
A Deserialize által visszaadott objektum lesz a mi osztályunk, csak object típusként kapjuk meg. A Deserialize függvény fogja aktivizálni az osztályunk új konstruktorát.
    private void button2_Click(object sender, System.EventArgs e)
    {
      FileStream fs = File.Open("x.dat", FileMode.Open);
      BinaryFormatter bf = new BinaryFormatter();
      TestClass tc = (TestClass)bf.Deserialize(fs);
      fs.Close();
      label1.Text = tc.A.ToString();
      label2.Text = tc.B;
    }