是否可以在 Silverlight 中使用 protobuf-net 对私有属性进行(反)序列化? [英] Is it possible to (de)serialize a private property using protobuf-net in Silverlight?

查看:54
本文介绍了是否可以在 Silverlight 中使用 protobuf-net 对私有属性进行(反)序列化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们知道 Silverlight 不允许私人反射.不过,我有一个带有私有 setter 的公共属性,我需要能够序列化(这里没问题)和反序列化(无赖).

As we know Silverlight does not allow private reflection. Still, I have a public property with a private setter, which I need to be able to serialize (no problem here) and deserialize (bummer).

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

I know that nothing in the world would make protobuf-net write to this property in Silverlight, this must be done from within the client type (or assembly, if the property is made internal).

protobuf-net 中是否有适用于 Silverlight 的方案,使之成为可能?我可以让类型实现一些专门的 protobuf-net 接口(例如 IProtoSerializable).

Is there a scheme in place in protobuf-net for Silverlight, which makes it possible? I could make the type implement some specialized protobuf-net interface (like IProtoSerializable, for instance).

谢谢.

编辑

我可以提出这样的方案:

I can propose a scheme like that:

[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 对象.

Where the type ProtoValue is public, but its constructors are internal, so that only protobuf-net assembly can create instances of that type. And of course, protobuf-net will not expose any public API to create ProtoValue objects.

此方案仅支持 Silverlight 平台,其他平台只会调用私有 setter.

This scheme can be supported for Silverlight platform only, other platforms will just invoke the private setter.

你怎么看?

EDIT2

我想指出,当然人们仍然可以获得对任意 PropValue 的引用.实例,但这不会是偶然的,这些是我希望消除的属性的意外覆盖.另外,我想让 setter 保持非公开状态,这样它就不会出现在 UI 中使用的各种基于反射的绑定机制中.

I wish to note that surely one can still obtain a reference to an arbitrary PropValue<T> instance, but this will not be accidentally and these are the accidental overwrites of the property, that I wish to eliminate. Plus, I want to keep the setter non public, so that it does not surface in various reflection based binding mechanisms used in UI.

EDIT3

PropValue实例可能不适合存储,这意味着在 DeserializePropValue 方法返回后,相应的 PropValue 实例将失效.这仅剩下一种滥用它的方式,如下所示:

The PropValue<T> instances can be made unsuitable for storage, meaning after the method DeserializePropValue returns, the respective PropValue instance is invalidated. This leaves only one way to abuse it, like so:

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

相当多的努力是偶然发生的.至于故意滥用 - 这里没有退步.人们总是可以序列化一个对象,操作二进制序列化数据,然后将其反序列化.回归仅在于滥用的容易程度.但是,我的目标是:

Quite a lot of effort to happen by accident. As to intentional abuse - there is no regression here. One can always serialize an object, manipulate the binary serialization data and then deserialize it back. The regression is only in the ease of abuse. However, my goal is to:

  • 防止意外错误
  • 保持 setter 非公开
  • 避免与代理相关的维护噩梦.

推荐答案

有趣的问题. v2 中有一个代理"的概念,它是为不可变对象(和结构)设计的,它可能有用——这取决于对象的复杂程度以及一个选项的吸引力.第二种选择可能是使属性表现出冰棒不变性.我将说明两者,但是:

Interesting question. There is a concept of "surrogates" in v2, which was designed for immutable objects (and structs), which might be of use - it depends how complex the object is as to how attractive an option that is. A second option might be to make the property exhibit popsicle immutability. I will illustrate both, but:

  • 在这种情况下,冰棒的不变性只是半冰棒,很容易被回避;这个选项很方便,如果你只是想防止意外损坏可能会很有用
  • 真正的不变性为您提供更强大的保护;本质上,代理充当构建器",但绝不允许您改变现有实例

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

Note that surrogates can't be specified on an attribute at the moment (I might add that later ;p) - so I've used the runtime model to demonstrate this:

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 这样的东西.我还在等待找到一件真正需要它的东西......我不确定这就是它.

I don't currently have anything like an IProtoSerializable. I'm still waiting to find that one thing that truly needs it... I'm not sure this is it.

这篇关于是否可以在 Silverlight 中使用 protobuf-net 对私有属性进行(反)序列化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆