是否可以在Silverlight中使用protobuf-net对私有财产进行反序列化?

mar*_*ark 3 protobuf-net

众所周知,Silverlight不允许私人反思。不过,我有一个带有私有设置器的公共财产,我需要能够序列化(这里没有问题)和反序列化(bummer)。

我知道世界上没有什么东西能使protobuf-net在Silverlight中写入此属性,这必须从客户端类型(或汇编,如果该属性为内部属性)中完成。

protobuf-net中是否存在针对Silverlight的方案,这使其成为可能?我可以使该类型实现一些专用的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;
}
Run Code Online (Sandbox Code Playgroud)

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

此方案仅可用于Silverlight平台,其他平台仅会调用私有设置程序。

你怎么看?

编辑2

我希望指出,可以肯定的是,仍然可以获取对任意PropValue <T>实例的引用,但这不是偶然的,这些是该属性的意外覆盖,我希望消除。另外,我想让设置器不公开,这样它就不会在UI中使用的各种基于反射的绑定机制中浮出水面。

编辑3

可以使PropValue <T>实例不适合存储,这意味着在方法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);
  }
}
Run Code Online (Sandbox Code Playgroud)

偶然发生的事情很多。至于故意虐待-这里没有回归。人们总是可以序列化一个对象,操纵二进制序列化数据,然后反序列化它。回归只是为了容易滥用。但是,我的目标是:

  • 防止意外错误
  • 保持二传手不公开
  • 避免与代孕相关的维护噩梦。

Mar*_*ell 5

有趣的问题。还有在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; }
}
Run Code Online (Sandbox Code Playgroud)

我目前没有类似的产品IProtoSerializable。我仍在等待寻找真正需要它的一件事……我不确定这是它。