I have a value object class (UserData) that is marked as Serializable and contains another class (StringType) that is marked as Serializable and implements ISerializable so that it can return singleton instances. The StringType class serializes and deserializes its own on it, but when it is used as a property for another object that is marked as Serializable, I get an exception for converting from the deserialization helper class to singleton.
An object of type "Spring2.Core.Test.Serialization.StringType_DEFAULT" cannot be converted to a type of "Spring2.Core.Test.Serialization.StringType".
I am using BinaryFormatter and should use this to save this UserData object in an ASP.NET session using SQL Server repository.
Here's a very stripped down version of the StringType class, as well as some tests that show that serialization / deserialization works for StringType on their own, but not when this field is in UserData.
StringType:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
using System.Security.Permissions;
namespace Spring2.Core.Test.Serialization {
public enum TypeState : short {
DEFAULT,
VALID,
UNSET
}
[Serializable]
public struct StringType : ISerializable {
private string myValue;
private TypeState myState;
public static readonly StringType DEFAULT = new StringType(TypeState.DEFAULT);
public static readonly StringType UNSET = new StringType(TypeState.UNSET);
private StringType(TypeState state) {
myState = state;
myValue = "";
}
public StringType(String s) {
myValue = s;
myState = TypeState.VALID;
}
public bool IsValid {
get { return myState == TypeState.VALID; }
}
public bool IsDefault {
get { return myState == TypeState.DEFAULT; }
}
public bool IsUnset {
get { return myState == TypeState.UNSET; }
}
public override string ToString() {
return IsValid ? this.myValue : myState.ToString();
}
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
StringType(SerializationInfo info, StreamingContext context) {
myValue = (System.String)info.GetValue("myValue", typeof(System.String));
myState = (TypeState)info.GetValue("myState", typeof(TypeState));
}
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
if (this.Equals(DEFAULT)) {
info.SetType(typeof(StringType_DEFAULT));
} else if (this.Equals(UNSET)) {
info.SetType(typeof(StringType_UNSET));
} else {
info.SetType(typeof(StringType));
info.AddValue("myValue", myValue);
info.AddValue("myState", myState);
}
}
}
[Serializable]
public class StringType_DEFAULT : IObjectReference {
public object GetRealObject(StreamingContext context) {
return StringType.DEFAULT;
}
}
[Serializable]
public class StringType_UNSET : IObjectReference {
public object GetRealObject(StreamingContext context) {
return StringType.UNSET;
}
}
}
Tests:
using System;
using NUnit.Framework;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace Spring2.Core.Test.Serialization {
[TestFixture]
public class DataTypeSerializationTest {
[Test]
public void ShouldBinarySerializeStringTypeWithValue() {
BinaryFormatter binaryFmt = new BinaryFormatter();
StringType s = new StringType("foo");
FileStream fs = new FileStream("foo.dat", FileMode.OpenOrCreate);
binaryFmt.Serialize(fs, s);
fs.Close();
Console.WriteLine("Original value: {0}", s.ToString());
fs = new FileStream("foo.dat", FileMode.OpenOrCreate);
StringType s2 = (StringType)binaryFmt.Deserialize(fs);
Console.WriteLine("New value: {0}", s2.ToString());
fs.Close();
Assert.AreEqual(s.ToString(), s2.ToString());
}
[Test]
public void ShouldBinarySerializeStringTypeUnset() {
BinaryFormatter binaryFmt = new BinaryFormatter();
StringType s = StringType.UNSET;
FileStream fs = new FileStream("foo.dat", FileMode.OpenOrCreate);
binaryFmt.Serialize(fs, s);
fs.Close();
Console.WriteLine("Original value is UNSET: {0}", s.IsUnset);
fs = new FileStream("foo.dat", FileMode.OpenOrCreate);
StringType s2 = (StringType)binaryFmt.Deserialize(fs);
Console.WriteLine("new value is UNSET: {0}", s2.IsUnset);
fs.Close();
Assert.IsTrue(s2.IsUnset);
}
[Test]
public void ShouldDeserializeDataObject() {
BinaryFormatter binaryFmt = new BinaryFormatter();
UserData u = new UserData();
FileStream fs = new FileStream("foo.dat", FileMode.OpenOrCreate);
binaryFmt.Serialize(fs, u);
fs.Close();
Console.WriteLine("Original value is UNSET: {0}", u.Name.IsUnset);
fs = new FileStream("foo.dat", FileMode.OpenOrCreate);
Object o = binaryFmt.Deserialize(fs);
UserData u2 = (UserData)o;
Console.WriteLine("new value is UNSET: {0}", u2.Name.IsUnset);
fs.Close();
Assert.IsTrue(Object.Equals(u, u2));
}
}
[Serializable]
public class UserData {
private StringType name = StringType.DEFAULT;
public StringType Name {
get { return name; }
set { name = value; }
}
}
}
Any help would be greatly appreciated!
Cort