I have a class that is effectively a object based enum. There is a static set of objects exposed by the class, and everything uses these same instances. eg (Note the private constructor)
[DataContract]
public class FieldType
{
public static readonly FieldType Default = new FieldType(1, "Default");
public static readonly FieldType Name = new FieldType(2, "Name");
public static readonly FieldType Etc = new FieldType(3, "Etc");
private FieldType(uint id, string name)
{
Id = id;
Name = name;
}
[DataMember] public uint Id { get; private set; }
[DataMember] public string Name { get; private set; }
//snip other properties
}
This works great until I have to serialise across WCF. The DataContractSerializer
creates new objects by bypassing the constructor. This results in a valid FieldType
object, but it is a new instance that is not one of my static instances. This makes reference comparisons against the known static values fail.
Is there any way to override the serialisation behaviour for a class so that I create the object instance instead of populating an instance supplied to me?
I suspect you can do:
[DataContract]
public class FieldType : IObjectReference
{
object IObjectReference.GetRealObject(StreamingContext ctx)
switch(Id) {
case 1: return Default;
case 2: return Name; // note this is a collision between static/non-static
case 3: return Etc;
default: throw new InvalidOperationException();
}
}
public static readonly FieldType Default = new FieldType(1, "Default");
// note this is a collision between static/non-static
public static readonly FieldType Name = new FieldType(2, "Name");
public static readonly FieldType Etc = new FieldType(3, "Etc");
private FieldType(uint id, string name)
{
Id = id;
Name = name; // note this is a collision between static/non-static
}
[DataMember] public uint Id { get; private set; }
// note this is a collision between static/non-static
[DataMember] public string Name { get; private set; }
//snip other properties
}
Validated:
public static class Program
{
static void Main()
{
var obj = FieldType.Default;
using(var ms = new MemoryStream())
{
var ser = new DataContractSerializer(typeof (FieldType));
ser.WriteObject(ms, obj);
ms.Position = 0;
var obj2 = ser.ReadObject(ms);
bool pass = ReferenceEquals(obj, obj2); // true
}
}
}
Note, however, that there seems little point serializing the Name
if we only use the Id
to identify the real object to use.