是否可以在 Silverlight 中使用 protobuf-net 来(反)序列化私有财产?
众所周知,Silverlight 不允许私有反射。尽管如此,我还是有一个带有私有设置器的公共财产,我需要能够对其进行序列化(这里没有问题)和反序列化(令人沮丧)。
我知道世界上没有任何东西可以使 protobuf-net 写入 Silverlight 中的此属性,这必须在客户端类型(或程序集,如果属性是内部的)内完成。
Silverlight 的 protobuf-net 中是否有一个使之成为可能的方案?我可以使该类型实现一些专门的 protobuf-net 接口(例如 IProtoSerialized)。
谢谢。
编辑
我可以提出这样的方案:
[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 平台,其他平台只会调用私有 setter。
你怎么认为?
EDIT2
我想指出的是,人们肯定仍然可以获得对任意 PropValue
EDIT3
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 不公开
- 避免与代理相关的维护噩梦。
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).
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).
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).
Thanks.
EDIT
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;
}
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.
This scheme can be supported for Silverlight platform only, other platforms will just invoke the private setter.
What do you think?
EDIT2
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
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:
- Prevent mistakes by accident
- Keep the setter non public
- Avoid the maintenance nightmare associated with surrogates.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
有趣的问题。 v2 中有一个“代理”的概念,它是为不可变对象(和结构)设计的,这可能有用 - 这取决于对象的复杂程度以及选项的吸引力。第二种选择可能是使属性表现出冰棒不变性。我将说明两者,但是:
请注意,目前无法在属性上指定代理(我可能会稍后添加;p) - 所以我使用了运行时模型来演示这一点:
我目前没有类似
IProtoSerialized
的东西。我仍在等待找到真正需要它的一件事......我不确定就是这个。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:
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:
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.看起来 Jackson - Java Json 序列化器很好地解决了不可变类问题: http ://www.cowtowncoder.com/blog/archives/2010/08/entry_409.html
基本上注释工厂/构造函数方法并将其输入参数映射到不可变/只读属性。
Looks like Jackson - the Java Json serializer solved the immutable class problem quite nicely: http://www.cowtowncoder.com/blog/archives/2010/08/entry_409.html
Basically annotate on the factory/constructor method and map its input parameters to immutable/read only properties.