Home Random Page


CATEGORIES:

BiologyChemistryConstructionCultureEcologyEconomyElectronicsFinanceGeographyHistoryInformaticsLawMathematicsMechanicsMedicineOtherPedagogyPhilosophyPhysicsPolicyPsychologySociologySportTourism






Nbsp;   Serializing a Type As a Different Type and Deserializing an Object As a Different Object

The .NET Framework’s serialization infrastructure is quite rich, and in this section, we discuss how a developer can design a type that can serialize or deserialize itself into a different type or object. Below are some examples where this is interesting:

■ Some types (such as System.DBNull and System.Reflection.Missing) are designed to have only one instance per AppDomain. These types are frequently called singletons. If you have a reference to a DBNull object, serializing and deserializing it should not cause a new DBNull object to be created in the AppDomain. After deserializing, the returned reference should refer to the AppDomain’s already-existing DBNull object.

■ Some types (such as System.Type, System.Reflection.Assembly, and other reflection types like MemberInfo) have one instance per type, assembly, member, and so on. Imagine you have an array where each element references a MemberInfo object. It’s possible that five array elements reference a single MemberInfo object. After serializing and deserializing this array, the five elements that referred to a single MemberInfo object should all refer to a single MemberInfo object. What’s more, these elements should refer to the one MemberInfo object that exists for the specific member in the AppDomain. You could also imagine how this could be useful for polling database connection objects or any other type of object.

■ For remotely controlled objects, the CLR serializes information about the server object that, when deserialized on the client, causes the CLR to create a proxy object. This type of the proxy object is a different type than the server object, but this is transparent to the client code. When the client calls instance methods on the proxy object, the proxy code internally remotes the call to the server that actually performs the request.

Let’s look at some code that shows how to properly serialize and deserialize a singleton type.

 

// There should be only one instance of this type per AppDomain [Serializable]

public sealed class Singleton : ISerializable {

// This is the one instance of this type

private static readonly Singleton s_theOneObject = new Singleton();

 

// Here are the instance fields public String Name = "Jeff";

public DateTime Date = DateTime.Now;

 

// Private constructor allowing this type to construct the singleton private Singleton() { }

 

// Method returning a reference to the singleton

public static Singleton GetSingleton() { return s_theOneObject; }


// Method called when serializing a Singleton

// I recommend using an Explicit Interface Method Impl. Here [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)] void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {

info.SetType(typeof(SingletonSerializationHelper));

// No other values need to be added

}

 

[Serializable]

private sealed class SingletonSerializationHelper : IObjectReference {



// Method called after this object (which has no fields) is deserialized public Object GetRealObject(StreamingContext context) {

return Singleton.GetSingleton();

}

}

 

// NOTE: The special constructor is NOT necessary because it's never called

}

 

The Singleton class represents a type that allows only one instance of itself to exist per App- Domain. The following code tests the Singleton’s serialization and deserialization code to ensure that only one instance of the Singleton type ever exists in the AppDomain.

 

private static void SingletonSerializationTest() {

// Create an array with multiple elements referring to the one Singleton object Singleton[] a1 = { Singleton.GetSingleton(), Singleton.GetSingleton() }; Console.WriteLine("Do both elements refer to the same object? "

+ (a1[0] == a1[1])); // "True"

 

using (var stream = new MemoryStream()) { BinaryFormatter formatter = new BinaryFormatter();

 

// Serialize and then deserialize the array elements formatter.Serialize(stream, a1);

stream.Position = 0;

Singleton[] a2 = (Singleton[])formatter.Deserialize(stream);

 

// Prove that it worked as expected:

Console.WriteLine("Do both elements refer to the same object? "

+ (a2[0] == a2[1])); // "True"

Console.WriteLine("Do all elements refer to the same object? "

+ (a1[0] == a2[0])); // "True"

}

}

 

Now, let’s walk through the code to understand what’s happening. When the Singleton type is loaded into the AppDomain, the CLR calls its static constructor, which constructs a Singleton object and saves a reference to it in a static field, s_theOneObject. The Singleton class doesn’t offer any public constructors, which prevents any other code from constructing any other instances of this class.


In SingletonSerializationTest, an array is created consisting of two elements; each element references the Singleton object. The two elements are initialized by calling Singleton’s static GetSingleton method. This method returns a reference to the one Singleton object. The first call to Console’s WriteLine method displays “True,” verifying that both array elements refer to the same exact object.

Now, SingletonSerializationTest calls the formatter’s Serialize method to serialize the ar- ray and its elements. When serializing the first Singleton, the formatter detects that the Singleton type implements the ISerializable interface and calls the GetObjectData method. This method calls SetType, passing in the SingletonSerializationHelper type, which tells the formatter to serialize the Singleton object as a SingletonSerializationHelper object instead. Because Add­ Value is not called, no additional field information is written to the stream. Because the formatter automatically detected that both array elements refer to a single object, the formatter serializes only one object.

After serializing the array, SingletonSerializationTest calls the formatter’s Deserial­ ize method. When deserializing the stream, the formatter tries to deserialize a Singleton­ SerializationHelper object because this is what the formatter was “tricked” into serializing. (In fact, this is why the Singleton class doesn’t provide the special constructor that is usually required when implementing the ISerializable interface.) After constructing the Singleton­ SerializationHelper object, the formatter sees that this type implements the System.

Runtime.Serialization.IObjectReference interface. This interface is defined in the FCL as

follows.

 

public interface IObjectReference {

Object GetRealObject(StreamingContext context);

}

 

When a type implements this interface, the formatter calls the GetRealObject method. This method returns a reference to the object that you really want a reference to now that deserializa- tion of the object has completed. In my example, the SingletonSerializationHelper type has GetRealObject return a reference to the Singleton object that already exists in the AppDomain. So, when the formatter’s Deserialize method returns, the a2 array contains two elements, both of which refer to the AppDomain’s Singleton object. The SingletonSerializationHelper object used to help with the deserialization is immediately unreachable and will be garbage collected in the future.

The second call to WriteLine displays “True,” verifying that both of a2’s array elements refer to the exact same object. The third and last call to WriteLine also displays “True,” proving that the ele- ments in both arrays all refer to the exact same object.



Date: 2016-03-03; view: 765


<== previous page | next page ==>
Nbsp;   Streaming Contexts | Nbsp;   Serialization Surrogates
doclecture.net - lectures - 2014-2024 year. Copyright infringement or personal data (0.007 sec.)