protobuf-net是否支持ArraySegment(目前)?

3

我已经阅读了Protobuf-net memcache provider fails on append/set ArraySegment,其中提到可能在某个时间点支持它。

我也尝试了该问题中建议的测试,结果表明版本2.0.0.668不支持它。

有没有人成功地使用ArraySegments和protobuf-net,或者有没有一个有效的方法来快速地通过网络发送字节数组。

即,我有这样一个对象:

[ProtoContract] 
class Foo
{
    [ProtoMember(1)]
    public byte[] Data { get; set; }
}

我希望能将另一个对象T序列化为字节数组,然后将其分配给Data,再将Foo序列化到另一个byte[]中。尽管可能效率不高,但Foo类必须对类型不可知,因此可以使用泛型吗?

关键是,我希望最小化分配/GC,并尽量减少每次序列化数据时数组的复制或新建分配。

以下是一些示例代码,演示了更有效地实现我想要的结果:

public class DataSender<T>
{
    private ISerializer serializer; //Could be any kind of binary serializer 
    public void Send(T obj)
    {
        MemoryStream serializationBuffer = new MemoryStream(); // Inefficent allocation
        serializer.Serialize(serializationBuffer, obj);
        var sendable = new Foo(){ Data=serializationBuffer.ToArray() } // Inefficent copy
        Sender.Send(sendable);
     }
}

如果您有替代Foo对象的建议和/或代码发送,请随时告知。


1
感谢您对格式进行编辑,我是用手机发布的! - JoshSub
1
短版:目前不行。代码可能并不是非常难,只是时间总是不够用,工作总是太多。 - Marc Gravell
1个回答

1

我觉得这看起来过于复杂。我认为你的将Foo泛型化的想法相当不错,所以你可以有:

[ProtoContract]
class Foo<T>
{
    [ProtoMember(1)]
    public T Data { get; set; }
}

然后,你可以使用简单的代码实例化一个新对象,例如:

var foo = new Foo<Bar>() { Data = new Bar() { Data = "Some Data" } };

然而,根据您的附加评论,您无法保证对象是可序列化的,或具有原型属性。例如,bar类可能如下所示:
class Bar
{
    public string Data { get; set; }
}

在这种情况下,您可以使用RuntimeTypeModel类来在运行时配置序列化。
以下是一个使用protobuf进行完全序列化和反序列化的示例,使用动态运行时配置数据对象:
using (var serializationBuffer = new MemoryStream())
{
    var foo = new Foo<Bar>() { Data = new Bar() { Data = "Some Data" } };

    RuntimeTypeModel.Default.Add(foo.Data.GetType(), false)
        .Add(foo.GetType().GetProperties().Select(p => p.Name).ToArray());

    Serializer.Serialize(serializationBuffer, foo);

    serializationBuffer.Seek(0, SeekOrigin.Begin);

    var deserialized = Serializer.Deserialize<Foo<Bar>>(serializationBuffer);
}

这样,您可以使用任何对象作为数据对象,即使它没有序列化属性。但是,由于使用反射来发现类型属性,因此会有性能损失。不过,您应该能够获得所需的灵活性
使用protobuf ProtoEndpointBehavior 配置WCF自定义行为,以正确地通过WCF发送此对象。然后,WCF将自动使用protobuf对Foo对象进行序列化和反序列化。这意味着客户端只需确保使用带有proto属性的对象并将其发送到网络上。WCF将负责序列化/反序列化。
以下是一个综合示例,说明如何使用WCF protobuf服务:

http://www.drdobbs.com/windows/working-with-protobuf-wcf-services/240159282?pgno=1

发送数据的效率取决于许多因素。如果您要通过电线发送大型对象,则可以将WCF TransferMode设置为使用Streaming,然后在另一端以字节数组块读取数据。
但是,效率是应该测量而不是假定的东西。

抱歉我的问题没有表述清楚,我已经更新了它以反映这一点。我不能确保使用协议缓冲区使Bar()可序列化,只能确保它是可序列化的。 - JoshSub
@JoshSub,我已更新我的示例以支持没有序列化属性的类型。看看吧。 - Faris Zacina
感谢@TheZenCoder,这确实提供了一种避免分配/复制额外缓冲区的解决方案。不确定是否会使用它,因为我还想允许我的库的客户端提供自己的ISerializer。我找到了另一个问题,https://dev59.com/rmbWa4cB1Zd3GeqPVlIf,我认为这展示了一种回退到此方法作为便捷默认值的方式。 - JoshSub
最终我无法使用这个,因为我意识到在连接的一端,进程不理解也不关心Bar的类型。它想要处理byte[]。然而,我会将这个答案接受,因为在问题中我从未指定过这一点。 - JoshSub

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接