Protobuff.net 无法序列化接口
Protobuff.net can't serialise Interface
我遇到了错误
The type cannot be changed once a serializer has been generated
尝试使用 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
引起的。如果我将此 class 更改为:
[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;
}
}
}
}
界面……很尴尬。好消息是你可以在代码中给它一个额外的提示(在你开始序列化之前):
Serializer.PrepareSerializer<ITest>();
如果代码能够提前更好地检测到这一点,那就太好了,但是:现在上面的内容应该有所帮助。因此,作为示例,我将这段代码放在静态类型初始值设定项中:
static Handler1()
{
Serializer.PrepareSerializer<ITest>();
}
但它也可以进入 global.asax 或 在您开始序列化之前 发生的任何其他地方。
我遇到了错误
The type cannot be changed once a serializer has been generated
尝试使用 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
引起的。如果我将此 class 更改为:
[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;
}
}
}
}
界面……很尴尬。好消息是你可以在代码中给它一个额外的提示(在你开始序列化之前):
Serializer.PrepareSerializer<ITest>();
如果代码能够提前更好地检测到这一点,那就太好了,但是:现在上面的内容应该有所帮助。因此,作为示例,我将这段代码放在静态类型初始值设定项中:
static Handler1()
{
Serializer.PrepareSerializer<ITest>();
}
但它也可以进入 global.asax 或 在您开始序列化之前 发生的任何其他地方。