是否可以在 Silverlight 中使用 protobuf-net 对私有属性进行(反)序列化?
Posted
技术标签:
【中文标题】是否可以在 Silverlight 中使用 protobuf-net 对私有属性进行(反)序列化?【英文标题】:Is it possible to (de)serialize a private property using protobuf-net in Silverlight? 【发布时间】:2011-05-19 18:34:28 【问题描述】:我们知道 Silverlight 不允许私有反射。不过,我有一个带有私有设置器的公共属性,我需要能够对其进行序列化(这里没问题)和反序列化(很糟糕)。
我知道世界上没有任何东西可以让 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 平台,其他平台只会调用私有 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 不公开 避免与代理相关的维护噩梦。【问题讨论】:
我仍在阅读编辑内容,但重新考虑了反射/绑定 API - 只需添加[ReadOnly(true)]
(msdn.microsoft.com/en-us/library/…)
我还没有尝试过代码,但我想知道是否只有一个 method(而不是属性)来设置值可以让我们充分地到达那里。即[Obsolete("Use this and I kill you")] public void SetProp(string value) ...
(也许还有一些东西告诉 protobuf-net 使用这种方法,但它也可以是基于模式的)
当然,我同意。我只想要一个阴影设置器方法。
@mark 酷;我可以做到 :) 我担心的是我已经非常努力允许使用不想了解 protobuf 详细信息的类型(朴素的 POCO 等) - 所以制作 protobuf 类型的一部分API 是不可取的。如果您对采用字符串的方法感到满意,那几乎没有任何工作。给我几天? (管道中的其他东西等)
使用 ObsoleteAttribute 时,还可以使用带布尔值的重载。当这个bool为真时,使用该方法时会出现编译错误。我在应仅由序列化程序使用的无参数构造函数上使用 [Obsolete("only for serialization", true)]。
【参考方案1】:
有趣的问题。 在 v2 中有一个“代理”的概念,它是为不可变对象(和结构)设计的,它可能有用 - 它取决于对象的复杂程度以及选项的吸引力有多大.第二种选择可能是使属性显示popsicle 不变性。我将说明两者,但是:
在这种情况下冰棒不变性只是半冰棒,很容易被绕过;此选项很方便,如果您只是想防止意外损坏,可能会很有用 真正的不变性给你更强的保护;本质上,代理充当“构建器”,但绝不允许您改变现有实例请注意,目前不能在属性上指定代理(我可能会在稍后添加;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
之类的东西。我还在等待找到真正需要它的东西……我不确定是不是它。
【讨论】:
我真的不喜欢冰棒的方法。但是,对于代理方法,我有一些不明白的地方。如果我有一个具有 10 个属性的类型,其中只有一个是只读的,我是否必须编写一个包含所有 10 个属性的代理,只是因为其中只有一个是只读的?似乎是一场维护噩梦。顺便说一句,你能解释一下是什么让你拒绝了我的提议吗? @mark - 在某种程度上,我不确定这给了你什么。例如,它看起来很容易被滥用。重新驳回它 - 恰恰相反,如果我们可以在这里添加一些有助于而不是漏洞的东西,我会全力以赴。不过,我的目标是提供示例,说明现在,今天可以作为起点。 我已编辑我的问题以解释我对滥用问题的看法。 在您的第二个隐式运算符定义中,将参数命名为“代理”非常令人困惑。还是我误解了什么?【参考方案2】:看起来像 Jackson - Java Json 序列化器很好地解决了不可变类问题:http://www.cowtowncoder.com/blog/archives/2010/08/entry_409.html
基本上在工厂/构造方法上注解,并将其输入参数映射到不可变/只读属性。
【讨论】:
我不确定如何弥合 java+json 和 silverlight+protobuf 之间的差距。你如何比较靴子和苹果? 在我看来,这个想法看起来很有希望。完全不变性,然后注释构造函数参数以允许反序列化,如下所示:private ImmutableType([ProtoMemberReference(nameof(this.ReadOnlyInt))] int readOnlyInt)
以上是关于是否可以在 Silverlight 中使用 protobuf-net 对私有属性进行(反)序列化?的主要内容,如果未能解决你的问题,请参考以下文章
是否可以在 Silverlight 电子邮件上创建电子邮件附件?
在 Silverlight 中获取当前 Windows 用户名
是否可以从 WebPart 获得对 silverlight 页面的引用?