众所周知,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)
偶然发生的事情很多。至于故意虐待-这里没有回归。人们总是可以序列化一个对象,操纵二进制序列化数据,然后反序列化它。回归只是为了容易滥用。但是,我的目标是:
有趣的问题。还有是在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。我仍在等待寻找真正需要它的一件事……我不确定这是它。
| 归档时间: |
|
| 查看次数: |
3965 次 |
| 最近记录: |