【问题标题】:Protobuff.net can't serialise InterfaceProtobuff.net 无法序列化接口
【发布时间】:2016-11-17 15:03:18
【问题描述】:

我收到了错误

序列化器一旦生成就不能改变类型

尝试使用 Protobuff.net 进行序列化时。我已设法减少代码以找到罪魁祸首,但想知道为什么它无法序列化此属性。

我找到了一个我可以使用的有效解决方案,但我对解释此代码失败的原因很感兴趣。

不会序列化:

[ProtoContract]
public class SomeController
{
    [ProtoMember(3)]
    public int ControllerValue { get; set; }

    [ProtoMember(4, AsReference = true)]
    private ITest ITestObj { get; set; }

    private SomeController(){}
    public SomeController(object something, int value)
    {
        ControllerValue = value;
        ITestObj = something as ITest;
    }
}

将序列化:

错误是由SomeController.ITestObj 引起的。如果我将此类更改为:

[ProtoContract]
public class SomeController
{
    [ProtoMember(3)]
    public int ControllerValue { get; set; }

    [ProtoMember(4, AsReference = true)]
    private TestObj OriginalObject { get; set; }

    private ITest ITestObj => OriginalObject as ITest;

    private SomeController(){}
    public SomeController(TestObj something, int value)
    {
        ControllerValue = value;
        OriginalObject = something;
    }
}

效果很好。

工作代码:

下面是一个独立的 HTTP 处理程序,它将运行此代码并重现错误:

using System.IO;
using System.Web;
using ProtoBuf;

namespace Handlers
{
    /// <summary>
    /// Summary description for Test
    /// </summary>
    public class Test : IHttpHandler
    {
        [ProtoContract]
        public class TestObj : ITest
        {
            [ProtoMember(1, AsReference = true)]
            public SomeController SomeController { get; set; }

            [ProtoMember(2)]
            public int SomeValue { get; set; }

            private TestObj(){}
            public TestObj(int something)
            {
                SomeController = new SomeController(this, something + 1);
                SomeValue = something;
            }
        }

        [ProtoContract]
        public class SomeController
        {
            [ProtoMember(3)]
            public int ControllerValue { get; set; }

            [ProtoMember(4, AsReference = true)]
            private ITest ITestObj { get; set; }

            private SomeController() { }
            public SomeController(object something, int value)
            {
                ControllerValue = value;
                ITestObj = something as ITest;
            }
        }

        [ProtoContract]
        [ProtoInclude(5, typeof(TestObj))]
        public interface ITest
        {
            [ProtoMember(6, AsReference = true)]
            SomeController SomeController { get; set; }

            [ProtoMember(7)]
            int SomeValue { get; set; }
        }


        public void ProcessRequest(HttpContext context)
        {
            var testObj = new TestObj(5);
            var serialised = Serialiser.Serialise(testObj);
            var deserialised = Serialiser.Deserialise<TestObj>(serialised);
            HttpContext.Current.Response.Write(deserialised.SomeValue + "|" + deserialised.SomeController.ControllerValue + "<br>");
        }

        protected internal class Serialiser
        {
            protected internal static byte[] Serialise<T>(T objectToSerialise)
            {
                using (var stream = new MemoryStream())
                {
                    Serializer.Serialize(stream, objectToSerialise);
                    return stream.ToArray();
                }
            }

            protected internal static T Deserialise<T>(byte[] bytes)
            {
                using (var stream = new MemoryStream(bytes))
                {
                    return Serializer.Deserialize<T>(stream);
                }
            }
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

【问题讨论】:

  • 您发布的代码(“它将运行此代码并重现错误”)对我来说很好,没有任何错误;我看到5|6。你能告诉我你用的是什么版本吗?什么运行时?
  • @MarcGravell 道歉,发布的代码是针对固定解决方案的。已将其更新为损坏的。使用 Protobuff.net 版本 2.1.0.0 运行时版本 v4.0.30319。如果对象被正确序列化/反序列化,则 5|6 是预期的输出。

标签: c# serialization protocol-buffers protobuf-net


【解决方案1】:

界面......很尴尬。好消息是你可以在代码中给它一个额外的提示(在你开始序列化之前):

Serializer.PrepareSerializer<ITest>();

如果代码可以提前更好地检测到这一点,那就太好了,但是:现在上面应该有所帮助。举个例子,我把这段代码放在静态类型初始化器中:

static Handler1()
{
    Serializer.PrepareSerializer<ITest>();
}

但它也可以进入 global.asax 或在您开始序列化之前发生的任何其他地方。

【讨论】:

  • 谢谢,这很有魅力!非常感谢您对这些库所做的帮助和工作。
猜你喜欢
  • 1970-01-01
  • 2013-08-02
  • 2010-10-14
  • 1970-01-01
  • 2015-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多