Is it possible to serialize/deserialize immutable types with protobuf-net on Windows Phone 7/8?

让人想犯罪 __ 提交于 2019-12-10 20:00:00

问题


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();
            }
        }
}

回答1:


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));



回答2:


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...



来源:https://stackoverflow.com/questions/16064466/is-it-possible-to-serialize-deserialize-immutable-types-with-protobuf-net-on-win

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!