【问题标题】:Does protobuf-net support ArraySegment (yet?)protobuf-net 是否支持 ArraySegment(还没有?)
【发布时间】:2014-10-22 08:50:08
【问题描述】:

我已阅读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 序列化为另一个字节 []。 (听起来效率低下,但 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 对象和/或发送代码的建议。

【问题讨论】:

  • 感谢格式编辑,从我的手机发布!
  • 短版:“不,目前没有”。代码可能并不难——只是时间问题(永远不够)/工作(总是太多)

标签: c# serialization protobuf-net binary-serialization


【解决方案1】:

这对我来说似乎过于复杂。我认为您将Foo 设为通用的想法非常好,因此您可以:

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

然后您将使用以下简单代码实例化一个新对象:

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

但是,根据您的附加 cmets,您不能保证该对象是可序列化的,或者具有 proto 属性。例如 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);
}

这样您就可以使用 any 对象作为您的数据对象,即使它没有序列化属性。但是,您会受到性能的损失,因为反射是用来发现类型属性的。但是,您应该获得所需的灵活性

使用 WCF 通过网络发送此对象的正确方法是使用 protobuf ProtoEndpointBehavior 配置 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,我已经更新了我的示例以支持没有序列化属性的类型。看看吧。
  • 感谢@TheZenCoder,这确实提供了一种避免分配/复制额外缓冲区的解决方案。不确定我是否会使用它,因为我还想让我的图书馆的客户提供他们自己的 ISerializer。我确实找到了另一个问题,stackoverflow.com/questions/11569593/…,我认为它展示了一种将这种方法作为一种方便的默认方式回退的方法。
  • 最后我无法使用它,因为我意识到在连接的一端,该过程不理解或关心 Bar 的类型。它想处理字节[]。但是,我将保留这个已接受的答案,因为我从未在问题中指定这一点。
猜你喜欢
  • 1970-01-01
  • 2012-09-16
  • 1970-01-01
  • 2011-06-13
  • 2021-11-15
  • 2021-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多