使用 Bond 嵌套对象
Nested objects with Bond
我正在尝试使用 Microsoft Bond 序列化嵌套对象。但是邦德抛出内部错误(例如 KeyNotFoundException)。
我的class是:
interface IFoo
{
}
[Bond.Schema]
class Foo1 : IFoo
{
[Bond.Id(0)]
public string Foo1Field { get; set; }
}
[Bond.Schema]
class Bar
{
[Bond.Id(0)]
public IFoo SomeFooInstance { get; set; }
}
然后我创建一个实例并序列化:
var src = new Bar() { SomeFooInstance = new Foo1() { Foo1Field = "Str" }};
var output = new OutputBuffer();
var writer = new CompactBinaryWriter<OutputBuffer>(output);
Serialize.To(writer, src);
var input = new InputBuffer(output.Data);
var reader = new CompactBinaryReader<InputBuffer>(input);
var dst = Deserialize<Bar>.From(reader);
但我在 Serialize.To(writer, src);
.
处遇到异常(例如 KeyNotFoundException)
我也尝试将 [Bond.Schema]
添加到 IFoo
,但是 Deserialize<Bar>.From(reader);
失败了...
如何使用 Bond 序列化包含一些 Foo
class 的 Bar
class 而不会出现这样的异常?
如果你想使用具有行为差异(而不是结构差异)的接口,诀窍是为反序列化器提供工厂,以便它知道如何在需要时创建 IFoo
的具体实例到。请注意,实现 没有 具有 [Bond.Schema]
属性,因为它们都实现了 IFoo
模式。
namespace NS
{
using System;
using Bond.IO.Unsafe;
using Bond.Protocols;
internal static class Program
{
[Bond.Schema]
interface IFoo
{
[Bond.Id(10)]
string FooField { get; set; }
}
[Bond.Schema]
class Bar
{
[Bond.Id(20)]
public IFoo SomeFooInstance { get; set; }
}
class AlwaysUppercaseFoo : IFoo
{
private string fooField;
public string FooField
{
get
{
return fooField;
}
set
{
fooField = value.ToUpperInvariant();
}
}
}
class IdentityFoo : IFoo
{
public string FooField { get; set; }
}
public static Expression NewAlwaysUppercaseFoo(Type type, Type schemaType, params Expression[] arguments)
{
if (schemaType == typeof(IFoo))
{
return Expression.New(typeof(AlwaysUppercaseFoo));
}
// tell Bond we don't handle the requested type, so it should use it's default behavior
return null;
}
public static Expression NewIdentityFoo(Type type, Type schemaType, params Expression[] arguments)
{
if (schemaType == typeof(IFoo))
{
return Expression.New(typeof(IdentityFoo));
}
// tell Bond we don't handle the requested type, so it should use it's default behavior
return null;
}
public static void Main(string[] args)
{
var src = new Bar() { SomeFooInstance = new IdentityFoo() { FooField = "Str" } };
var output = new OutputBuffer();
var writer = new CompactBinaryWriter<OutputBuffer>(output);
Bond.Serialize.To(writer, src);
{
var input = new InputBuffer(output.Data);
var deserializer = new Bond.Deserializer<CompactBinaryReader<InputBuffer>>(typeof(Bar), NewAlwaysUppercaseFoo);
var reader = new CompactBinaryReader<InputBuffer>(input);
var dst = deserializer.Deserialize<Bar>(reader);
Debug.Assert(dst.SomeFooInstance.FooField == "STR");
}
{
var input = new InputBuffer(output.Data);
var deserializer = new Bond.Deserializer<CompactBinaryReader<InputBuffer>>(typeof(Bar), NewIdentityFoo);
var reader = new CompactBinaryReader<InputBuffer>(input);
var dst = deserializer.Deserialize<Bar>(reader);
Debug.Assert(dst.SomeFooInstance.FooField == "Str");
}
}
}
}
如果您需要行为和结构差异,那么您需要将它与 polymorphism 和一个 bonded<IFoo>
字段配对,这样您就可以延迟反序列化,直到您有足够的类型信息来 select正确的实现。 (多态性是显式的,opt-in 在 Bond 中。)
我会展示一个例子,但是在 2018-02-21 写这个答案时,我发现了一个bug in the handling of classes with [Bond.Schema]
that implement interfaces with [Bond.Schema]
:接口中的字段被省略了。
目前,解决方法是对 类 使用继承并使用虚拟属性。例如:
namespace NS
{
using System;
using Bond.IO.Unsafe;
using Bond.Protocols;
internal static class Program
{
enum FooKind
{
Unknown = 0,
AlwaysUppercase = 1,
Identity = 2,
}
// intentionally a class to work around https://github.com/Microsoft/bond/issues/801 but simulate an interface somewhat
[Bond.Schema]
class IFoo
{
[Bond.Id(0)]
public virtual string FooField { get; set; }
}
[Bond.Schema]
class Bar
{
[Bond.Id(0)]
public Bond.IBonded<IFoo> SomeFooInstance { get; set; }
[Bond.Id(1)]
public FooKind Kind { get; set; }
}
[Bond.Schema]
class AlwaysUppercaseFoo : IFoo
{
private string fooField;
public override string FooField
{
get
{
return fooField;
}
set
{
fooField = value.ToUpperInvariant();
}
}
[Bond.Id(0)]
public string JustAlwaysUppercaseFooField { get; set; }
}
[Bond.Schema]
class IdentityFoo : IFoo
{
[Bond.Id(42)]
public string JustIdentityFooField { get; set; }
}
static void RoundTripAndPrint(Bar src)
{
var output = new OutputBuffer();
var writer = new CompactBinaryWriter<OutputBuffer>(output);
Bond.Serialize.To(writer, src);
var input = new InputBuffer(output.Data);
var reader = new CompactBinaryReader<InputBuffer>(input);
var dst = Bond.Deserialize<Bar>.From(reader);
switch (dst.Kind)
{
case FooKind.Identity:
{
var fooId = dst.SomeFooInstance.Deserialize<IdentityFoo>();
Console.WriteLine($"IdFoo: \"{fooId.FooField}\", \"{fooId.JustIdentityFooField}\"");
}
break;
case FooKind.AlwaysUppercase:
{
var fooUc = dst.SomeFooInstance.Deserialize<AlwaysUppercaseFoo>();
Console.WriteLine($"UcFoo: \"{fooUc.FooField}\", \"{fooUc.JustAlwaysUppercaseFooField}\"");
}
break;
default:
Console.WriteLine($"Unknown Kind: {dst.Kind}");
break;
}
}
public static void Main(string[] args)
{
var o = new OutputBuffer();
var w = new CompactBinaryWriter<OutputBuffer>(o);
Bond.Serialize.To(w, new IdentityFoo() { FooField = "Str", JustIdentityFooField = "id" });
var src_id = new Bar()
{
SomeFooInstance = new Bond.Bonded<IdentityFoo>(new IdentityFoo() { FooField = "Str", JustIdentityFooField = "id" }),
Kind = FooKind.Identity
};
var src_uc = new Bar()
{
SomeFooInstance = new Bond.Bonded<AlwaysUppercaseFoo>(new AlwaysUppercaseFoo() { FooField = "Str", JustAlwaysUppercaseFooField = "I LIKE TO YELL!" }),
Kind = FooKind.AlwaysUppercase
};
RoundTripAndPrint(src_id);
RoundTripAndPrint(src_uc);
}
}
}
这会打印:
IdFoo: "Str", "id"
UcFoo: "STR", "I LIKE TO YELL!"
我正在尝试使用 Microsoft Bond 序列化嵌套对象。但是邦德抛出内部错误(例如 KeyNotFoundException)。
我的class是:
interface IFoo
{
}
[Bond.Schema]
class Foo1 : IFoo
{
[Bond.Id(0)]
public string Foo1Field { get; set; }
}
[Bond.Schema]
class Bar
{
[Bond.Id(0)]
public IFoo SomeFooInstance { get; set; }
}
然后我创建一个实例并序列化:
var src = new Bar() { SomeFooInstance = new Foo1() { Foo1Field = "Str" }};
var output = new OutputBuffer();
var writer = new CompactBinaryWriter<OutputBuffer>(output);
Serialize.To(writer, src);
var input = new InputBuffer(output.Data);
var reader = new CompactBinaryReader<InputBuffer>(input);
var dst = Deserialize<Bar>.From(reader);
但我在 Serialize.To(writer, src);
.
我也尝试将 [Bond.Schema]
添加到 IFoo
,但是 Deserialize<Bar>.From(reader);
失败了...
如何使用 Bond 序列化包含一些 Foo
class 的 Bar
class 而不会出现这样的异常?
如果你想使用具有行为差异(而不是结构差异)的接口,诀窍是为反序列化器提供工厂,以便它知道如何在需要时创建 IFoo
的具体实例到。请注意,实现 没有 具有 [Bond.Schema]
属性,因为它们都实现了 IFoo
模式。
namespace NS
{
using System;
using Bond.IO.Unsafe;
using Bond.Protocols;
internal static class Program
{
[Bond.Schema]
interface IFoo
{
[Bond.Id(10)]
string FooField { get; set; }
}
[Bond.Schema]
class Bar
{
[Bond.Id(20)]
public IFoo SomeFooInstance { get; set; }
}
class AlwaysUppercaseFoo : IFoo
{
private string fooField;
public string FooField
{
get
{
return fooField;
}
set
{
fooField = value.ToUpperInvariant();
}
}
}
class IdentityFoo : IFoo
{
public string FooField { get; set; }
}
public static Expression NewAlwaysUppercaseFoo(Type type, Type schemaType, params Expression[] arguments)
{
if (schemaType == typeof(IFoo))
{
return Expression.New(typeof(AlwaysUppercaseFoo));
}
// tell Bond we don't handle the requested type, so it should use it's default behavior
return null;
}
public static Expression NewIdentityFoo(Type type, Type schemaType, params Expression[] arguments)
{
if (schemaType == typeof(IFoo))
{
return Expression.New(typeof(IdentityFoo));
}
// tell Bond we don't handle the requested type, so it should use it's default behavior
return null;
}
public static void Main(string[] args)
{
var src = new Bar() { SomeFooInstance = new IdentityFoo() { FooField = "Str" } };
var output = new OutputBuffer();
var writer = new CompactBinaryWriter<OutputBuffer>(output);
Bond.Serialize.To(writer, src);
{
var input = new InputBuffer(output.Data);
var deserializer = new Bond.Deserializer<CompactBinaryReader<InputBuffer>>(typeof(Bar), NewAlwaysUppercaseFoo);
var reader = new CompactBinaryReader<InputBuffer>(input);
var dst = deserializer.Deserialize<Bar>(reader);
Debug.Assert(dst.SomeFooInstance.FooField == "STR");
}
{
var input = new InputBuffer(output.Data);
var deserializer = new Bond.Deserializer<CompactBinaryReader<InputBuffer>>(typeof(Bar), NewIdentityFoo);
var reader = new CompactBinaryReader<InputBuffer>(input);
var dst = deserializer.Deserialize<Bar>(reader);
Debug.Assert(dst.SomeFooInstance.FooField == "Str");
}
}
}
}
如果您需要行为和结构差异,那么您需要将它与 polymorphism 和一个 bonded<IFoo>
字段配对,这样您就可以延迟反序列化,直到您有足够的类型信息来 select正确的实现。 (多态性是显式的,opt-in 在 Bond 中。)
我会展示一个例子,但是在 2018-02-21 写这个答案时,我发现了一个bug in the handling of classes with [Bond.Schema]
that implement interfaces with [Bond.Schema]
:接口中的字段被省略了。
目前,解决方法是对 类 使用继承并使用虚拟属性。例如:
namespace NS
{
using System;
using Bond.IO.Unsafe;
using Bond.Protocols;
internal static class Program
{
enum FooKind
{
Unknown = 0,
AlwaysUppercase = 1,
Identity = 2,
}
// intentionally a class to work around https://github.com/Microsoft/bond/issues/801 but simulate an interface somewhat
[Bond.Schema]
class IFoo
{
[Bond.Id(0)]
public virtual string FooField { get; set; }
}
[Bond.Schema]
class Bar
{
[Bond.Id(0)]
public Bond.IBonded<IFoo> SomeFooInstance { get; set; }
[Bond.Id(1)]
public FooKind Kind { get; set; }
}
[Bond.Schema]
class AlwaysUppercaseFoo : IFoo
{
private string fooField;
public override string FooField
{
get
{
return fooField;
}
set
{
fooField = value.ToUpperInvariant();
}
}
[Bond.Id(0)]
public string JustAlwaysUppercaseFooField { get; set; }
}
[Bond.Schema]
class IdentityFoo : IFoo
{
[Bond.Id(42)]
public string JustIdentityFooField { get; set; }
}
static void RoundTripAndPrint(Bar src)
{
var output = new OutputBuffer();
var writer = new CompactBinaryWriter<OutputBuffer>(output);
Bond.Serialize.To(writer, src);
var input = new InputBuffer(output.Data);
var reader = new CompactBinaryReader<InputBuffer>(input);
var dst = Bond.Deserialize<Bar>.From(reader);
switch (dst.Kind)
{
case FooKind.Identity:
{
var fooId = dst.SomeFooInstance.Deserialize<IdentityFoo>();
Console.WriteLine($"IdFoo: \"{fooId.FooField}\", \"{fooId.JustIdentityFooField}\"");
}
break;
case FooKind.AlwaysUppercase:
{
var fooUc = dst.SomeFooInstance.Deserialize<AlwaysUppercaseFoo>();
Console.WriteLine($"UcFoo: \"{fooUc.FooField}\", \"{fooUc.JustAlwaysUppercaseFooField}\"");
}
break;
default:
Console.WriteLine($"Unknown Kind: {dst.Kind}");
break;
}
}
public static void Main(string[] args)
{
var o = new OutputBuffer();
var w = new CompactBinaryWriter<OutputBuffer>(o);
Bond.Serialize.To(w, new IdentityFoo() { FooField = "Str", JustIdentityFooField = "id" });
var src_id = new Bar()
{
SomeFooInstance = new Bond.Bonded<IdentityFoo>(new IdentityFoo() { FooField = "Str", JustIdentityFooField = "id" }),
Kind = FooKind.Identity
};
var src_uc = new Bar()
{
SomeFooInstance = new Bond.Bonded<AlwaysUppercaseFoo>(new AlwaysUppercaseFoo() { FooField = "Str", JustAlwaysUppercaseFooField = "I LIKE TO YELL!" }),
Kind = FooKind.AlwaysUppercase
};
RoundTripAndPrint(src_id);
RoundTripAndPrint(src_uc);
}
}
}
这会打印:
IdFoo: "Str", "id" UcFoo: "STR", "I LIKE TO YELL!"