是否可以在Silverlight中使用protobuf-net(de)序列化私有财产?

时间:2011-05-19 18:34:29

标签: protobuf-net

我们知道Silverlight不允许私人反思。尽管如此,我还有一个带有私有setter的公共属性,我需要能够序列化(这里没问题)和反序列化(bummer)。

我知道世界上没有任何东西会让protobuf-net在Silverlight中写入此属性,这必须在客户端类型(或程序集,如果属性是内部的)内完成。

是否有适用于Silverlight的protobuf-net的计划,这有可能吗?我可以使类型实现一些专门的protobuf-net接口(例如IProtoSerializable)。

感谢。

修改

我可以提出这样的计划:

[ProtoMember(N, SetterMethod = "DeserializePropValue")]
public string property Prop
{
  get { return m_prop; }
  private set { m_prop = value; }
}

public void DeserializePropValue(ProtoValue<string> value)
{
  m_prop = value.Value;
}

ProtoValue类型是公共的,但其构造函数是内部的,因此只有protobuf-net程序集才能创建该类型的实例。当然,protobuf-net不会公开任何公共API来创建ProtoValue对象。

此方案仅支持Silverlight平台,其他平台只会调用私有设置器。

您怎么看?

EDIT2

我希望注意到,当然仍然可以获得对任意PropValue&lt; T&gt;的引用。例如,但这不会是偶然的,这些是财产的意外覆盖,我希望消除。另外,我想让setter不公开,因此它不会出现在UI中使用的各种基于反射的绑定机制中。

EDIT3

PropValue&lt; T&gt;实例可能不适合存储,这意味着在DeserializePropValue方法返回后,相应的PropValue实例将失效。这只留下一种方式滥用它,如下:

[ProtoContract]
public class Abusee
{
    [ProtoMember(1, SetterMethod = "DeserializePropValue")]
    public string property Prop { get; private set; }

    public void DeserializePropValue(ProtoValue<string> value)
    {
      m_prop = value.Value;
    }
}

[ProtoContract]
public class Abuser
{
  private Abusee m_abusee;

  public Abuser(Abusee abusee, string newPropValue)
  {
    m_abusee = abusee;
    Dummy = newPropValue;
    Serializer.DeepClone(this);
  }

  [ProtoMember(1, SetterMethod = "DeserializeDummyValue")]
  public string property Dummy
  {
    get;
    private set;
  }

  public void DeserializeDummyValue(ProtoValue<string> value)
  {
    m_abusee.DeserializePropValue(value);
  }
}

偶然发生了很多努力。至于故意滥用 - 这里没有回归。可以始终序列化对象,操作二进制序列化数据,然后将其反序列化。回归只是在容易滥用。但是,我的目标是:

  • 意外防止错误
  • 让setter非公开
  • 避免与代理人相关的维护噩梦。

2 个答案:

答案 0 :(得分:4)

有趣的问题。 在v2中的“代理”概念,它是为不可变对象(和结构)设计的,它可能是有用的 - 它取决于对象的复杂程度,以及选项的吸引力程度。 。第二种选择可能是使该属性展示冰棒不变性。我将说明两者,但是:

  • 冰棒不变性在这种情况下只是半冰棒,很容易被踩到一边;此选项很方便,如果您只是想防止意外损坏,这可能很有用
  • 真正的不变性为您提供更强大的保护;本质上,代理人充当“建设者”,但从不允许你改变现有的实例

请注意,目前无法在属性上指定代理项(稍后我可能会添加; p) - 所以我使用运行时模型来演示:

class Program
{
    static void Main()
    {
        var obj = new Popsicle(3, 4);
        var clone = Serializer.DeepClone(obj);
        Debug.Assert(clone.Foo == obj.Foo);
        Debug.Assert(clone.Bar == obj.Bar);

        var model = TypeModel.Create();
        model.Add(typeof(MutableSurrogate), false).Add("Foo", "Bar");
        model.Add(typeof(ImmutableType), false).SetSurrogate(typeof(MutableSurrogate));
        // note you should re-use models (cache them) - or better: pre-generate a serializer dll
        var obj2 = new ImmutableType(5, 6);
        var clone2 = (ImmutableType)model.DeepClone(obj2);
        Debug.Assert(clone2.Foo == obj2.Foo);
        Debug.Assert(clone2.Bar == obj2.Bar);
    }
}

[ProtoContract] // should also work with DataContract etc
public class Popsicle
{
    public Popsicle() { }
    public Popsicle(int foo, int bar)
    {
        Foo = foo;
        this.bar = bar;
    }
    private int isBeingDeserialized;

    [ProtoBeforeDeserialization]
    public void BeforeDeserialization()
    {
        isBeingDeserialized++;
    }
    [ProtoAfterDeserialization]
    public void AfterDeserialization()
    {
        isBeingDeserialized--;
    }
    [ProtoMember(1)]
    public int Foo { get; set; } //  fully mutable

    private int bar;
    [ProtoMember(2)]
    public int Bar
    {
        get { return bar; }
        set
        {
            if (bar == value) return;
            if (isBeingDeserialized <= 0) throw new InvalidOperationException();
            bar = value;
        }
    }
}

public class ImmutableType
{
    private readonly int foo, bar;
    public ImmutableType(int foo, int bar)
    {
        this.foo = foo;
        this.bar = bar;
    }
    public int Foo { get { return foo; } }
    public int Bar { get { return bar; } }
}
public class MutableSurrogate
{
    public static implicit operator ImmutableType(MutableSurrogate surrogate)
    {            
        return surrogate == null ? null
            : new ImmutableType(surrogate.Foo, surrogate.Bar);
    }
    public static implicit operator MutableSurrogate(ImmutableType surrogate)
    {
        return surrogate == null ? null
            : new MutableSurrogate { Foo = surrogate.Foo, Bar = surrogate.Bar };
    }
    public int Foo { get; set; }
    public int Bar { get; set; }
}

我目前没有类似IProtoSerializable的内容。我还在等着找到真正需要的东西......我不确定是不是。

答案 1 :(得分:1)

看起来杰克逊--Java Json序列化程序很好地解决了不可变类问题:http://www.cowtowncoder.com/blog/archives/2010/08/entry_409.html

基本上对工厂/构造函数方法进行注释,并将其输入参数映射到不可变/只读属性。

相关问题