Protobuff.net无法序列化接口

时间:2016-11-17 15:03:18

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

我收到了错误

  

生成序列化程序后无法更改类型

尝试使用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;
            }
        }
    }
}

1 个答案:

答案 0 :(得分:4)

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

Serializer.PrepareSerializer<ITest>();

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

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

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