April 2011 - Posts

Perbedaan call dan callvirt (Bagaimana CLR memanggil method)

Pada postingan kali ini saya ingin membahas tentang perbedaan call dan callvirt pada pemanggilan Method.

Dengan tujuan untuk mengetahui bagaimana sebenarnya CLR bertingkah laku ketika memanggil method.

Disini kita akan menggunakan dua buah class, yaitu Base yang mempunyai sebuah method SomeMethod

dan class Derived yang merupakan turunan dari class Base.

   1:  class First
   2:  {
   3:      protected int counter = 0;
   4:      public virtual void SomeMethod(int max)
   5:      {
   6:          Console.WriteLine("{0} - First.SomeMethod", " ");
   7:          if (counter != max) SomeMethod(max);
   8:      }
   9:  }
  10:  class Second : First
  11:  {
  12:      public override void SomeMethod(int max)
  13:      {
  14:          Console.WriteLine("{0} - Second.SomeMethod", ++counter);
  15:          base.SomeMethod(max);
  16:      }
  17:      static void Main()
  18:      {
  19:          Second s = new Second();
  20:          s.SomeMethod(9);
  21:   
  22:          Console.ReadLine();
  23:      }
  24:  }

Pada line 7 dan 15 First.SomeMethod akan dipanggil oleh CLR.

Disini CLR akan memperlakukan 2 pemanggilan tersebut dengan cara yang berbeda.

pada line 15 Second.SomeMethod akan memanggil First.SomeMethod menggunakan sintax "base.SomeMethod(max)"

yang mana First.SomeMethod akan dipanggil tidak secara virtual oleh CLR, ini bisa kita lihat pada IL code yang dihasilkan :

L_0024: call instance void First::SomeMethod(int32) 

Disini CLR akan memanggil SomeMethod yang ada pada First class tanpa mengecek apakah First.SomeMethod telah di override

oleh class turunannya.

pada line 7 First.SomeMethod akan memanggil dirinya sendiri (recursive) menggunakan sintax "SomeMethod(max)"

yang mana First.SomeMethod akan dipanggil secara virtual oleh CLR, ini bisa kita lihat pada IL code yang dihasilkan :

L_0020: callvirt instance void First::SomeMethod(int32)

Ketika SomeMethod dipanggil secara virtual maka CLR akan memanggil SomeMethod yang ada pada First class.

Lalu kemudian CLR akan mengecek apakah SomeMethod telah dioverride oleh class turunannya, jika iya maka SomeMethod

pada class turunannya yang akan di panggil (Second.SomeMethod)


Pemanggilan method secara virtual (callvirt) terjadi pada instance method yang kita deklarasikan sebagai virtual.

Pada instance method yang tidak dideklarasikan sebagai virtual maka pemanggilan method tetap akan terjadi secara virtual (callvirt).

Tetapi, pemanggilan virtual disini hanya untuk mengecek apakah instance dari class yang mendeklarasikan method tersebut sudah 

dicreate atau tidak (dengan kata lain untuk mengecek object null atau tidak) tetapi tidak mengecek apakah method tersebut di override atau tidak.

Sedangkan pada static method, method akan selalu di panggil langsung, tidak secara virtual.

Dan jika memanggil method menggunakan keyword base (seperti pada line 15) maka method juga akan di panggil langsung, tidak secara virtual.

Kalau misalnya memanggil method dengan keyword base (seperti pada line 15) di panggil secara virtual(callvirt) maka SomeMethod pada 

Second class akan dipanggil berulang-ulang yang menyebabkan stack over flow.

So, yang bisa kita ambil disini adalah, pendeklarasian method sebagai virtual akan membuat pemanggilan method lebih lama.

Karena CLR akan bekerja dua kali :

yaitu untuk mengecek apakah object null atau tidak, lalu untuk mengecek apakah method tersebut sudah di override atau tidak.

Itulah perbedaan antara call dan callvirt yang mengatur bagaimana CLR memanggil suatu method.

Kalau kita mengerti bagaimana tingkah laku dari CLR maka kita bisa menerapkannya untuk membuat aplikasi kita lebih

fleksibel. Seperti yang di praktekkan pada code diatas yang melakukan pemanggilan recursive (seperti pada line 15) tetapi selalu diakhiri dengan pemanggilan

method pada class turunannya (Second.SomeMethod).

output program :

Share this post: | | | |
Posted by Agus Syahputra with no comments
Filed under: , ,

base dan this adalah object yang sama, not different

Bagi yang belum tau sebenarnya kalau base dan this itu adalah mengacu pada object yang sama.

So, postingan kali ini ingin menunjukkan hal tersebut.

OK, perhatikan kode dibawah ini :

internal class Base
{
    internal static Object This;  
 
    //Alamat Base kita simpan didalam Base.This
    public Base() { This = this; }    
}
internal class Derived : Base
{
    internal static Object BaseAddress;
    internal Derived()
    {
        //Alamat Derived kita simpan didalam Derived.This
        This = this;
        BaseAddress = Base.This;
    }
}
 
internal static class Program
{
    private static void Main()
    {         
        Derived d = new Derived();
 
        //Cek apakah isi variable d dan Derived.ThisAddress sama
        Console.WriteLine("Are d and Derived.ThisAddress same ? :" + (d == Derived.This));
 
        //Cek apakah base dan this sama
        Console.WriteLine("Are base and this same ? :" + (Derived.BaseAddress == Derived.This));
        Console.ReadLine();
    }
}

Pada kode diatas, kita menyimpan alamat dari base pada Base.This lalu kita simpan kembali ke Derived.BaseAddress.

Lalu alamat dari Derived (this) kita simpan pada Derived.This.

Dan untuk membuktikan bahwa base dan this adalah mengacu pada object yang sama, kita mempergunakan static class Program.

Dan apabila Program di jalankan akan menampilkan bahwa base dan this mengacu pada object yang sama.

Jadi dari sini dapat kita analisa bahwa pada saat object Derived diinisialisasi,

maka struktur data dari Base dibuat dahulu oleh CLR, kemudian CLR membahkan struktur data Derived kedalam struktur data

dari Base, itulah sebabnya ketika  kita menginisialisasi Derived kita juga harus menginisialisasi Base dengan cara memanggil constructor

dari Base(Walaupun pada kode diatas kita tidak melakukannya karena telah dilakukan secara implisit oleh CLR) . So, intinya ketika kita

meng-create object Derived sebenarnya itu hanyalah terdiri dari satu object yaitu Derived saja dan bukan Base dan Derived.

Jadi, kalau misalnya ada kode seperti ini pada Base :

internal class Base
{    
    internal event EventHandler SameNumbers;
    private Random rnd = new Random();
    private Object key = new Object();
    private Int32? cache = null;
    internal void SetScrambler(Int32 left, Int32 top)
    {
        lock (key)
        {
            Thread.Sleep(50);
            Int32? temp = rnd.Next(0, 100);
            Console.SetCursorPosition(left, top);
            Console.Write(temp);
            if (temp == cache) OnSameNumbers(EventArgs.Empty);
            else cache = temp;
        }
    }
    internal void ScramblerGo()
    {
        ThreadPool.QueueUserWorkItem(arg => { while (true) SetScrambler(0, 0); });
        ThreadPool.QueueUserWorkItem(arg => { while (true) SetScrambler(4, 0); });
    }
    protected virtual void OnSameNumbers(EventArgs e)
    {
        EventHandler temp = SameNumbers;
        if (temp != null) temp(this, e);
    }
}
Lalu kita buat Derived dengan kode seperti ini :
internal class Derived : Base
{
    protected override sealed void OnSameNumbers(EventArgs e)
    {
        MessageBox.Show("OnSameNumbers : Numbers are same...");
        base.OnSameNumbers(e);
    }
}
Sebenarnya pada kode base.OnSameNumbers(e) diatas, Derived mengacu pada struktur datanya sendiri.
Karena memang object base itu dan object this adalah object yang sama.
Jadi sekali lagi, intinya CLR hanya membuat satu struktur data (object) yaitu object Derived saja
yang classnya bisa dijelaskan dengan pseudocode berikut :
internal class Derived 
{
    internal event EventHandler SameNumbers;
 
    //dengan catatan : fields private berikut ini ada(exist) distruktur data dari Derived
    //tetapi tidak bisa diakses dari Derived karena diprivatekan oleh Base
    private Random rnd = new Random();
    private Object key = new Object();
    private Int32? cache = null;
    internal void SetScrambler(Int32 left, Int32 top)
    {        
        lock (key)
        {
            Thread.Sleep(50);
            Int32? temp = rnd.Next(0, 100);
            Console.SetCursorPosition(left, top);
            Console.Write(temp);
            if (temp == cache) OnSameNumbers(EventArgs.Empty);
            else cache = temp;
        }
    }
    internal void ScramblerGo()
    {
        ThreadPool.QueueUserWorkItem(arg => { while (true) SetScrambler(0, 0); });
        ThreadPool.QueueUserWorkItem(arg => { while (true) SetScrambler(4, 0); });
    }
    private void OnSameNumbers(EventArgs e)
    {
        MessageBox.Show("OnSameNumbers : Numbers are same...");
        EventHandler temp = SameNumbers;
        if (temp != null) temp(this, e);
    }    
}

Itu sebabnya bila kita jalankan dengan static class Program berikut :

internal static class Program
{
    private static void Main()
    {
        Derived d = new Derived();
        d.SameNumbers += (sender, e) => MessageBox.Show("In Lambda : Numbers are same...");
        d.ScramblerGo();
        Console.ReadLine();
    }
}
Maka, "OnSameNumbers : Numbers are same..." akan tampil lebih dulu dari pada "In Lambda : Numbers are same...".
Karena memang pada kenyataannya pada class Derived "OnSameNumbers : Numbers are same..." ditampilkan terlebih
dahulu baru kemudian Event diRaise.
Share this post: | | | |
Posted by Agus Syahputra with 2 comment(s)
Filed under: ,

Threading Model dan Synchronization Context

Pada .Net Framework terdapat yang namanya threading model yang terkait dengan suatu application model.

Contohnya ASP.Net Web Application mempunyai threading modelnya sendiri, sementara Windows Forms mempunyai threading

modelnya sendiri.

Threading Model pada Windows forms yaitu, thread yang bisa meng-update state dari suatu control

adalah thread yang telah meng-create control tersebut. Jadi thread pool thread tidak di izinkan untuk untuk mengupdate state

dari suatu control.

Contohnya pada code di bawah ini, kita mempunya suatu method ResponseToFunc yang akan di invoke ketika

thread pool thread selesai meng-invoke method targetnya si delegate(Func<Int32, Int32>).

internal sealed class MyForm : Form
{       
    private static Func<Int32Int32> func = arg =>
    {        
        Int32 result = 0;
        for (Int32 i = 0; i < arg; i++)
        {
            Thread.Sleep(300);
            Console.WriteLine("Result : " + (result = i));
        }
        return result;
    };
       
    internal MyForm()
    {
        //Main Thread men-set state dari MyForm
        Console.WriteLine("Thread Name : {0}, IsThreadPoolThread : {1}",
            Thread.CurrentThread.Name, Thread.CurrentThread.IsThreadPoolThread);
        Width = Height = 400;        
    } 
    private void ResponseToFunc(IAsyncResult arg)
    {
        //ThreadPoolThread mengeksekusi method ini
        Console.WriteLine("IsThreadPoolThread : " + Thread.CurrentThread.IsThreadPoolThread);
        try
        {
            Int32 result = func.EndInvoke(arg);            
            Console.WriteLine("action complete, result = {0}", result);            
 
            //Thread Pool Thread tidak diizinkan untuk mengupdate state
            //dari suatu control, sehingga kode di bawah akan menyebabkan error.
            Text = "func complete";
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
 
    protected override void OnMouseClick(MouseEventArgs e)
    {        
        Text = "Initial Text";        
        func.BeginInvoke(5, ResponseToFunc, null);   
        base.OnMouseClick(e);
    }
}
internal static class Program
{    
    private static void Main()
    {        
        Thread.CurrentThread.Name = "MainThread";
        MyForm mf = new MyForm();
        Application.Run(mf); 
                 
        Console.ReadLine();
    }
} 

Pada code diatas akan menyebabkan error karena thread pool thread tidak di izinkan merubah Text dari form.



So, untuk meng-update Text dari MyForm maka kita harus menggunakan MainThread.

Karena MainThread yang menginisialisasi MyForm dan hanya MainThread yang bisa meng-update state dari MyForm.

Yang menjadi pertanyaan adalah "bagaimana kita bisa menggunakan MainThread dari dalam method(method ResponseToFunc) yang di eksekusi

oleh Thread Pool Thread ?"

Kita bisa menggunakan object SynchronizationContext untuk melaksanakan ini.

Kita mereferensi object dari SynchronizationContext dengan cara memanggil static property SynchronizationContext.Current

dari dalam method yang diakses oleh MainThread (dalam kasus ini method OnMouseClick).

Lalu kita panggil method Post dari object SynchronizationContext, dan kita isi parameternya dengan delegate yang method targetnya

berisi kode untuk meng-update Text dari MyForm. Untuk lebih jelasnya seperti dalam kode berikut :

internal sealed class MyForm : Form
{
    //field untuk menyimpan referensi dari object SynchronizationContext     
    private static SynchronizationContext syncContext; 
    private static Func<Int32Int32> func = arg =>
    {        
        Int32 result = 0;
        for (Int32 i = 0; i < arg; i++)
        {
            Thread.Sleep(300);
            Console.WriteLine("Result : " + (result = i));
        }
        return result;
    };
       
    internal MyForm()
    {
        //Main Thread men-set state dari MyForm
        Console.WriteLine("Thread Name : {0}, IsThreadPoolThread : {1}",
            Thread.CurrentThread.Name, Thread.CurrentThread.IsThreadPoolThread);        
        Width = Height = 400;        
    }
 
    //ResponseToFunc akan akan diinvoke setelah method target si delegate Func<Int32, Int32>
    //selesai di eksekusi
    private void ResponseToFunc(IAsyncResult arg)
    {
        //ThreadPoolThread mengeksekusi method ini
        Console.WriteLine("IsThreadPoolThread : " + Thread.CurrentThread.IsThreadPoolThread);
        try
        {
            Int32 result = func.EndInvoke(arg);            
            Console.WriteLine("action complete, result = {0}", result);
 
            //syncContext.Post akan menginvoke sebuah method yang meng-update
            //state dari MyForm dengan menggunakan MainThread.            
            syncContext.Post(arg => {
 
                //Update text dilakukan oleh MainThread 
                Text = "func complete";
            }, null);            
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
 
    protected override void OnMouseClick(MouseEventArgs e)
    {
        //Mendapatkan referensi ke object SynchronizationContext
        syncContext = SynchronizationContext.Current;
        Text = "Initial Text";        
        func.BeginInvoke(5, ResponseToFunc, null);   
        base.OnMouseClick(e);
    }
}



Gambar diatas menunjukkan MainThread berhasil mengupdate Text dari MainForm via
SynchronizationContext

 

Share this post: | | | |

Serialisasi pada object yang tidak serializable

Ini adalah kode yang menjelaskan bagaimana kita melakukan serialisasi pada object yang tidak serializable.

Disini kita menggunakan surrogate untuk melakukan serialization.

Dan apabila object yang akan kita serialkan tersebut ternyata type dari value-nya si field tidak serializable

maka field tersebut tetap kita serialkan tetapi valuenya kita set menjadi null.

 

//class SurrogateType yang meng-implementasi ISerializationSurrogate
//sebagai surrogate yang akan melaksanakan serialization 
//untuk type yang tidak serializable
internal sealed class SurrogateType : ISerializationSurrogate 
{
    //bindingflags sebagai flag yang menentukan karakterisitik field 
    //yang akan diserialkan
    private static BindingFlags bf = BindingFlags.Public | BindingFlags.Instance |
                                    BindingFlags.NonPublic | BindingFlags.Static;
 
    //obj(parameter pertama) adalah referensi ke object yang sesungguhnya(dalam hal ini object yang 
    //tipenya tidak serializable)
    public void GetObjectData(Object obj, SerializationInfo info, StreamingContext context)
    {        
        //mendapatkan semua fields pada object
        FieldInfo[] arr_fi = obj.GetType().GetFields(bf);
     
        //mendapatkan semua fields value pada object
        Object[] values = FormatterServices.GetObjectData(obj, arr_fi);
        Int32 counter=0;        
        
        foreach (var v in arr_fi)
        {
            //cek apakah field tidak sama dengan null
            if (v.GetValue(obj) != null)
            {
                //jika value-nya si field tidak sama dengan null, periksa apakah type value
                //dari si field menggunakan attribute serializable (jadi yang diperiksa
                //bukan type dari si field, melainkan type valuenya).
                //Jika hasilnya betul maka set SerializationInfo dengan nama si field, dan value si field.
                //Jika tidak, maka type value dari si field tidak serializable dan kita set
                //SerializationInfo dengan nama si field tapi dengan value null.
                if (v.GetValue(obj).GetType().IsDefined(typeof(SerializableAttribute), false))
                {
                    info.AddValue(v.Name, values[counter]);
                }
                else
                {
                    info.AddValue(v.Name, null);
                }
            }
            //jika field sama dengan null maka set SerializationInfo dengan nama si field
            //dan valuenya kita isi dengan null
            else
            {
                info.AddValue(v.Name, null);
            }
            counter++;            
        }        
    }
 
    //obj(parameter pertama) adalah referensi ke object yang sesungguhnya(dalam hal ini object yang 
    //tipenya tidak serializable) yang telah di serialkan dan sedang di deserialkan. Objectnya sendiri
    //sudah ada didalam memory karena sudah diinstan-kan oleh formatter tetapi fields-nya masih 
    //kosong
    public Object SetObjectData(Object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
    {   
        //mendapatkan semua fields dari object yang telah dibuat instan-nya oleh formatter
        //setelah serialization(dalam hal ini object masing kosong, fieldnya belum diisi
        //karena constructor tidak dipanggil dan method inilah yang akan meng-set fields
        //dari object tersebut) 
        //dan kita akan mengisi value dari fields tersebut dengan value yang terdapat
        //dalam object SerializationInfo
        FieldInfo[] arr_fi = obj.GetType().GetFields(bf);
                
        Object[] values = FormatterServices.GetObjectData(obj, arr_fi);                
        
        foreach (var v in arr_fi)
        {            
            v.SetValue(obj, info.GetValue(v.Name, v.FieldType));
        }        
        return obj;
    }
}
 
internal class Program
{
    private static Stream StreamMedium= new FileStream("file.txt"FileMode.Create);
    private static IFormatter formatter = new SoapFormatter();
    private static SurrogateSelector surrogate = new SurrogateSelector();
    private static Int32 Int32IsSerializable = 0;
    
    private static void SurrogateDemo(Object graph)
    {
        //print object sebelum serialisasi
        Console.WriteLine(graph);
 
        //assign tipe yang akan di-surrogate-kan
        surrogate.AddSurrogate(graph.GetType(), formatter.Context, new SurrogateType());
 
        //assign SurrogateSelector ke formatter
        formatter.SurrogateSelector = surrogate;
 
        //formatter akan menggunakan surrogate untuk melakukan 
        //serialization pada object
        formatter.Serialize(StreamMedium, graph);
 
        //nulling variabel graph
        graph = null;
        StreamMedium.Position = 0;
 
        //print state dari object yang telah diserialkan sebagai bukti
        //kalau serialization berhasil
        Console.WriteLine(new StreamReader(StreamMedium).ReadToEnd());
 
        ////formatter akan menggunakan surrogate untuk melakukan 
        //deserialization pada object
        graph = Deserializer(StreamMedium);
 
        //print object sebagai bukti kalau deserialisasi berhasil
        Console.WriteLine(graph);        
    }
 
    private static void Main()
    {        
        Object obj = new Program();
        SurrogateDemo(obj);        
    }
 
    public override string ToString()
    {
        return String.Format("Program.StreamMedium = {0}\n" +
                             "Program.formatter = {1}\n" +
                             "Program.surrogate = {2}\n" +
                             "Program.Int32IsSerializable = {3}\n",
                             StreamMedium, formatter, surrogate, Int32IsSerializable);
    }
}
Output Program :
Share this post: | | | |
Posted by Agus Syahputra with no comments

Munggunakan surrogate untuk melakukan serialisasi

Ini adalah sample kode yang menjelaskan bagaimana menggunakan surrogate untuk melakukan serialisasi.

Sehingga kita bisa take control pada class yang tidak melaksanakan ISerializable.

 

//class WillBeSurrogated yang tidak meng-implement ISerializable
[Serializable]
internal sealed class WillBeSurrogated
{
    private Int32 SerializedNumber;
 
    //field yang tidak diserialkan
    [NonSerialized]
    private Int32 UnserializedNumber;
    public WillBeSurrogated(Int32 SerializedNumber, Int32 UnserializedNumber)
    {
        this.SerializedNumber = SerializedNumber;
        this.UnserializedNumber = UnserializedNumber;
    }
    public override string ToString()
    {
        return String.Format("WillBeSurrogated.SerializedNumber = {0}\n" +
                             "WillBeSurrogated.UnserializedNumber = {1}\n", SerializedNumber, UnserializedNumber);
    }    
}
//class SurrogateType yang meng-implementasi ISerializationSurrogate //sebagai surrogate yang akan melaksanakan serialization  //untuk class WillBeSurrogated internal sealed class SurrogateType : ISerializationSurrogate  {     public void GetObjectData(Object obj, SerializationInfo info, StreamingContext context)     {         //mendapatkan fields dari obj WillBeSurrogated yang bisa diserialkan         MemberInfo[] arr_mi = FormatterServices.GetSerializableMembers(obj.GetType());         //mendapatkan value dari masing-masing fields di obj WillBeSurrogated         Object[] values = FormatterServices.GetObjectData(obj, arr_mi);         Int32 counter=0;         //menambahkan value dari obj WillBeSurrogated ke object SerializationInfo         foreach (var v in arr_mi)         {             info.AddValue(v.Name, values[counter]);              counter++;         }     }
    //obj pada parameter pertama adalah instant dari class WillBeSurrogated     //yang telah di-instantiate oleh formatter tapi belum diisi fields nya     public Object SetObjectData(Object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)     {         //mendapatkan fields dari obj WillBeSurrogated yang bisa di serialkan         MemberInfo[] arr_mi = FormatterServices.GetSerializableMembers(obj.GetType());         //mendapatkan value dari masing-masing fields di obj WillBeSurrogated         Object[] values = FormatterServices.GetObjectData(obj, arr_mi);                 FieldInfo fi;         //menambahkan value dari obj SerializationInfo ke object WillBeSurrogated         foreach (var v in arr_mi)         {             fi = (FieldInfo)v;             fi.SetValue(obj, info.GetValue(fi.Name, fi.FieldType));         }                 return obj;     } }
internal
 class Program {     private static Stream CacheStream;     private static IFormatter formatter;         private static void SurrogateDemo()     {         Object wbs = new WillBeSurrogated(10, 20);         Console.WriteLine(wbs);         CacheStream = new MemoryStream();         formatter = new BinaryFormatter();         SurrogateSelector ss = new SurrogateSelector();         //assign tipe yang akan di-surrogate-kan         ss.AddSurrogate(typeof(WillBeSurrogated), formatter.Context, new SurrogateType());         //assign SurrogateSelector ke formatter         formatter.SurrogateSelector = ss;         //formatter akan menggunakan surrogate untuk melakukan          //serialization pada obj wbs         formatter.Serialize(CacheStream, wbs);         //nulling variabel wbs         wbs = null;         CacheStream.Position = 0;         //formatter akan menggunakan surrogate untuk melakukan          //deserialization pada obj wbs         wbs = formatter.Deserialize(CacheStream);         Console.WriteLine(wbs);             }     private static void Main()     {         SurrogateDemo();     } }
Share this post: | | | |
Posted by Agus Syahputra with no comments
Filed under: ,

Implementasi ISerializable pada Derived Type yang Inherited dari Base Type Non ISerializable

Ketika kita mau meng-implement ISerializable pada Derived type yang inherited dari Base type yang telah meng-implement ISerializable,

biasanya kita memanggil base.GetObjectData. Seperti yang ditunjukkan pada kode berikut :

[Serializable]
class Base : ISerializable
{
    Int32 FirstNumber;
    Int32 UnserializedNumber;
    public Base(Int32 FirstNumber)
    {
        this.FirstNumber = FirstNumber;
        UnserializedNumber = FirstNumber * 10;
    }
    protected Base(SerializationInfo info, StreamingContext context)
    {
        FirstNumber = info.GetInt32("FirstNumber");
    }    
    public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("FirstNumber", FirstNumber);
    }
    public override String ToString()
    {
        return String.Format("FirstNumber = {0}\n" + 
                             "UnserializedNumber = {1}", FirstNumber, UnserializedNumber);
    }
}
[Serializable]
class Derived : BaseISerializable
{
    Int32 SecondNumber;
    public Derived(Int32 SecondNumber): base(SecondNumber)
    {
        this.SecondNumber = SecondNumber * 2;
    }
    Derived(SerializationInfo info, StreamingContext context) : base(info, context)
    {
        SecondNumber = info.GetInt32("SecondNumber");
    }
    public override void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("SecondNumber", SecondNumber);
 
        //memanggil base.GetObjectData() agar 
        //Serialization bisa berjalan dengan baik
        base.GetObjectData(info, context);
    } 
    public override string ToString()
    {
        return String.Format(base.ToString() + "\n" +
                            "SecondNumber = " + SecondNumber);
    }   
}
static class Program {     static MemoryStream CacheStream = null;         static BinaryFormatter formater = null;       static void Serializer(Object graph)     {         CacheStream = new MemoryStream();         formater = new BinaryFormatter();         formater.Serialize(CacheStream, graph);         Console.WriteLine("Serialization complete");     }     static Object Deserializer(MemoryStream stream)     {         formater = new BinaryFormatter();         FormatterConverter converter = new FormatterConverter();         stream.Position = 0;
return formater.Deserialize(stream);     }     static void Main()     {         Object d = new Derived(10);         Serializer(d);       
//nulling variable d         d = null;         d = Deserializer(CacheStream);         Console.WriteLine(d);             }     }
Tapi bagaimana apabila kita hendak meng-implement ISerializable pada Derived type
yang inherited dari Base type yang tidak meng-implement ISerializable ?  
Untuk melakukannya maka kita bisa mengenumerasi semua field dari object Derived dan menyimpannya kedalam object 
SerializationInfo, seperti yang ditunjukkan pada kode berikut sehingga object Derived bisa diserialkan.
[Serializable]
class BaseNotISerializable
{
    Int32 FirstNumber;
    Int32 UnserializedNumber;
    public BaseNotISerializable(Int32 FirstNumber)
    {
        this.FirstNumber = FirstNumber;
        UnserializedNumber = FirstNumber * 10;
    }
    public override String ToString()
    {
        return String.Format("FirstNumber = {0}\n" +
                             "UnserializedNumber = {1}", FirstNumber, UnserializedNumber);
    }
}
[Serializableclass DerivedISerializable : BaseNotISerializableISerializable  {     Int32 SecondNumber;     public DerivedISerializable(Int32 SecondNumber) : base(SecondNumber)     {         this.SecondNumber = SecondNumber * 2;     }         DerivedISerializable(SerializationInfo info, StreamingContext context) : base(0)     {         //mendapatkan semua field dari Derived yang bisa diserialkan         //dengan memanggil FormatterServices.GetSerializableMembers         MemberInfo[] arr_mi = FormatterServices.GetSerializableMembers(this.GetType());         FieldInfo fi;         //isi nilai semua field dengan value yang disimpan pada object SerializationInfo         foreach (var v in arr_mi)         {             fi=(FieldInfo)v;             fi.SetValue(this, info.GetValue(fi.Name, fi.FieldType));         }           }         public void GetObjectData(SerializationInfo info, StreamingContext context)     {         //mendapatkan semua field dari Derived yang bisa diserialkan         //dengan memanggil FormatterServices.GetSerializableMembers         MemberInfo[] arr_mi = FormatterServices.GetSerializableMembers(this.GetType());         FieldInfo fi;         //isi object SerializationInfo dengan nilai dari semua field          //yang ada pada derived dengan cara enumerasi         foreach (var v in arr_mi)         {             fi = (FieldInfo)v;             info.AddValue(fi.Name, fi.GetValue(this));         }             }     public override string ToString()     {         return String.Format(base.ToString() + "\n" +                             "SecondNumber = " + SecondNumber);     } }
static class Program
/*definition class Program*/     static void Main()     {         Object d = new DerivedISerializable(10);         Serializer(d);

//nulling variable d
        d = null;         d = Deserializer(CacheStream);         Console.WriteLine(d);     }     }
Share this post: | | | |
Posted by Agus Syahputra with no comments