我们知道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);
}
}
偶然发生了很多努力。至于故意滥用 - 这里没有回归。可以始终序列化对象,操作二进制序列化数据,然后将其反序列化。回归只是在容易滥用。但是,我的目标是:
答案 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
基本上对工厂/构造函数方法进行注释,并将其输入参数映射到不可变/只读属性。