Reputation: 7512
Is it possible to serialize/deserialize types with protobuf-net on Windows Phone 7/8?
I've tried the code below, it seems Constructor skipping isn't supported (i.e. UseConstructor = false) so I created a parameterless constructor but the deserialization fails with "Attempt to access the method failed: Wp7Tests.ImmutablePoint.set_X(System.Double)"
public class ImmutablePoint
{
public double X { get; private set; }
public double Y { get; private set; }
public ImmutablePoint() {}
public ImmutablePoint(double x, double y)
{
X = x;
Y = y;
}
}
public sub Test()
{
ImmutablePoint pt = new ImmutablePoint(1, 2);
var model = TypeModel.Create();
var ptType = model.Add(typeof(ImmutablePoint), false);
ptType.AddField(1, "X");
ptType.AddField(2, "Y");
IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();
using (var stream1 = new IsolatedStorageFileStream("test.bin", FileMode.Create, store))
{
try
{
model.Serialize(stream1, pt);
}
catch (Exception e)
{
Debugger.Break();
}
}
const double EPSILON = 0.001;
using (var stream1 = new IsolatedStorageFileStream("test.bin", FileMode.Open, store))
{
try
{
ImmutablePoint ptDeSer = (ImmutablePoint) model.Deserialize(stream1,null, typeof(ImmutablePoint));
Debug.Assert(Math.Abs(pt.X - ptDeSer.X) < EPSILON);
Debug.Assert(Math.Abs(pt.Y - ptDeSer.Y) < EPSILON);
}
catch (Exception e)
{
Debugger.Break();
}
}
}
Upvotes: 3
Views: 497
Reputation: 1063393
You can use a surrogate; here I'm decorating it with attributes, but it can be configured manually too:
[ProtoContract]
public class MutablePoint {
[ProtoMember(1)] public double X { get; set; }
[ProtoMember(2)] public double Y { get; set; }
public static implicit operator MutablePoint(ImmutablePoint value) {
return value == null ? null : new MutablePoint {X=value.X, Y=value.Y};
}
public static implicit operator ImmutablePoint(MutablePoint value) {
return value == null ? null : new ImmutablePoint(value.X, value.Y);
}
}
and then tell the model to use this whenever it sees ImmutablePoint
:
var model = TypeModel.Create();
model.Add(typeof(MutablePoint), true);
model.Add(typeof(ImmutablePoint), false).SetSurrogate(typeof(MutablePoint));
The serializer will use the operators to switch between them as necessary. The serializer will use either implicit
or explicit
custom conversion operators.
EDIT: Deserialize like this
ImmutablePoint ptDeSer = (ImmutablePoint)model.Deserialize(stream1, null, typeof(ImmutablePoint));
Upvotes: 8
Reputation: 1580
This isn't possible on Windows Phone. The deserializer cannot access the setters and using reflection to access private members results in a MemberAccessException on Windows Phone. The only way I can think of getting something like this to work would be by creating a wrapper for serialization which can then call the constructor of your ImmutablePoint. It's all a bit messy though as the wrapper class will need public read-write properties for X and Y.
You could also look at using the InternalsVisibleTo attribute to allow the serializer to access the properties (assuming you change the setters from private to internal). Still messy though...
Upvotes: 2