我们有以下内容..
public class Foo
{
public string Name { get; private set;}
private Foo(string name)
{
Name = name;
}
public Foo Instance1 = new Foo("Hello");
public Foo Instance2 = new Foo("World");
}
然后引用这个我们就有了..
[ProtoContract]
public class Bar
{
[ProtoMember(1)]
public Foo Foo { get; private set; }
public Bar(Foo foo)
{
Foo = foo;
}
}
所以当我反序列化一个Bar时,我需要它来获取对Foo.Instance1或Foo.Instance2的引用..
问题是我可以这样做,如果是这样的话?
答案 0 :(得分:2)
有几种方法可以解决这个问题。 最简单的将添加一个shim属性,即
public Foo Foo { get; private set; }
[ProtoMember(1)]
private SomeBasicEnum FooSerialization {
/* shim between Foo and SomeBasicEnum in get/set */
}
但是,如果你有很多Foo
属性,这可能会很痛苦。因此,相反,v2提供“代理”类型 - 即只要它可以在两种类型之间找到转换运算符,它就会很乐意自动交换它们。在这种情况下,我们要交换到枚举,因为您无法将运算符添加到枚举,您必须将运算符添加到Foo
:
public static implicit operator Foo(FooSurrogate value)
{
switch (value)
{
case FooSurrogate.Nil: return null;
case FooSurrogate.Instance1: return Foo.Instance1;
case FooSurrogate.Instance2: return Foo.Instance2;
default: throw new InvalidEnumArgumentException("value");
}
}
public static implicit operator FooSurrogate(Foo value)
{
if (value == null) return FooSurrogate.Nil;
if (value == Foo.Instance1) return FooSurrogate.Instance1;
if (value == Foo.Instance2) return FooSurrogate.Instance2;
throw new InvalidEnumArgumentException("value");
}
并在某处有一个简单的枚举:
public enum FooSurrogate
{
Nil, Instance1, Instance2
}
并配置它(在app-startup的某个地方):
RuntimeTypeModel.Default.Add(typeof(Foo), false).SetSurrogate(
typeof(FooSurrogate));
我们很高兴。还需要一个小调整,因为Bar
缺少无参数构造函数;这里有2个选项:
private Bar() {}
[ProtoContract(SkipConstructor = true)]
添加测试台:
static void Main()
{
RuntimeTypeModel.Default.Add(typeof(Foo), false).SetSurrogate(
typeof(FooSurrogate));
var obj = new Bar(Foo.Instance1);
var clone = Serializer.DeepClone(obj);
bool same = ReferenceEquals(obj.Foo, clone.Foo);
Debug.Assert(same); // passes
}
我可能也可以使用外部运算符式方法来避免必须在Foo
上运行操作符,这有点难看。
最后一个选择是我添加IObjectReference
支持,但坦率地说(特别是在这种情况下),使用基本枚举来实现更整洁,更有效。