30
Mai
2006

Serialization with Reference Identity

Although I have very little time for Blog-related activities at the moment, I'd like to share with the rest of the world a solution to a problem which I think should be quite common: serialization which preserves reference identity. Sometimes you may have a class similar to this:

class Multiton {
  public static readonly Multiton Instance1 = new Multiton();
  public static readonly Multiton Instance2 = new Multiton();
  // ...

  private Multiton() {}

  // other useful methods
}
Note that this is similar to a singleton, just that it doesn't have just one single instance, but a defined number of single instances; hence the name "Multiton". I used this for an improved enum, i.e. an enumeration wrapper, which provided some instance methods. Does anyone know why C# doesn't allow you to do that with normal enum types, by the way? There shouldn't be a real technical reason against it, and it seems it works well in Java.

Okay, back to the topic: what happens if you serialize and then deserialize these instances? The serialization engine will create new instances of the Multiton class, which is not desireable at all.

Now, .NET serialization actually provides a workaround for such cases: IObjectReference. A class implementing this interface can be used as a serialization helper, providing a method GetRealObject, which is used by the serialization engine to query for the "real" object to be returned after the deserialization process. Unfortunately, all examples for IObjectReference I've found deal with singletons, so it took me some experimenting to apply the mechanism for my multiton. In the following, I'll provide a full multiton implementation with serialization support and a simple test driver:

using System;

using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;


namespace Serialization {
   [Serializable]
   public sealed class Multiton : ISerializable {
       public enum Kind { Undefined, One, Two }

       public static Multiton Instance1 = new Multiton(Kind.One);
       public static Multiton Instance2 = new Multiton(Kind.Two);

       public readonly Kind MyKind;

       private Multiton(Kind kind) {
           this.MyKind = kind;
       }


       // other constructor needs not be implemented,
       // it's never called


       public void GetObjectData(SerializationInfo info, StreamingContext context) {
           info.SetType(typeof(MultitonSerializationHelper));
           info.AddValue("kind", MyKind);
       }
   }

   [Serializable]
   class MultitonSerializationHelper : IObjectReference, ISerializable {

       public Multiton.Kind kind = Multiton.Kind.Undefined;


       public MultitonSerializationHelper(SerializationInfo info, StreamingContext context) {
           this.kind = (Multiton.Kind)info.GetValue("kind", typeof(Multiton.Kind));
       }

       void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
           // this is never called
           throw new NotImplementedException("This should never be called.");

       }

       public object GetRealObject(StreamingContext context) {
           switch (kind) {
               case Multiton.Kind.One:
                   return Multiton.Instance1;
               case Multiton.Kind.Two:
                   return Multiton.Instance2;
               default:
                   throw new Exception("object undefined!");
           }
       }
   }

   class Program {
       static void Main(string[] args) {
           BinaryFormatter formatter = new BinaryFormatter();
           byte[] data;

           using (MemoryStream stream = new MemoryStream()) {

               formatter.Serialize(stream, new Multiton[] {
                   Multiton.Instance2,
                   Multiton.Instance1,
                   Multiton.Instance1,
                   Multiton.Instance2});

               data = stream.GetBuffer();
           }

           using (MemoryStream stream = new MemoryStream(data)) {

               Multiton[] multitons = (Multiton[])formatter.Deserialize(stream);
               foreach (Multiton mt in multitons) {
                   if (object.ReferenceEquals(mt, Multiton.Instance1)) {
                       Console.Write("1 ");
                   }
                   else if (object.ReferenceEquals(mt, Multiton.Instance2)) {
                       Console.Write("2 ");
                   }
                   else {
                       Console.Write("? ");
                   }
               }
           }
           Console.WriteLine();
       }
   }
}
logo

fcs@tuwien

User Status

Du bist nicht angemeldet.

Suche

 

Aktuelle Beiträge

Mixins, and FCS@TUWIEN...
It's been a really long time since I last posted on...
fcs - 30. Jan, 15:04
I made another implementation...
I made another implementation of the generic WeakReference...
Patrik (anonym) - 22. Dez, 02:00
I'm Working - Some Figures
Besides using LINQ in order to break my Visual Studio...
fcs - 12. Dez, 10:32
LINQ CTP Breaks SmartTags
Do you know that very useful SmartTag feature provided...
fcs - 23. Nov, 11:25
Generic WeakReference...
For a pooling aspect I wrote today, I needed to use...
fcs - 14. Nov, 17:51

Status

Online seit 1464 Tagen
Zuletzt aktualisiert: 30. Jan, 15:06

Credits

twoday.org

based on antville powered by Helma


  • xml version of this page

AOF
C# and .NET
Meta
Personal
Windows
Profil
Abmelden
Weblog abonnieren