我正在使用protobuf-net v2 beta r431进行C#.net 4.0应用程序。在我的应用程序中,我有一个Dictionary<int, IMyClass>
我需要序列化。类MyClass
实现IMyClass
接口。根据protobuf的文档,我编写了以下代码:
[ProtoContract]
[ProtoInclude(1, typeof(MyClass))]
public interface IMyClass
{
int GetId();
string GetName();
}
[ProtoContract]
[Serializable]
public class MyClass : IMyClass
{
[ProtoMember(1)]
private int m_id = 0;
[ProtoMember(2)]
private string m_name = string.Empty;
public MyClass(int id, string name)
{
m_id = id;
m_name = name;
}
public MyClass()
{
}
#region IMyClass Members
public int GetId()
{
return m_id;
}
public string GetName()
{
return m_name;
}
#endregion
}
但是,根据我的应用程序的设计,接口是在更高级别(在与项不同的项目中)定义的,并且无法确定在编译时实现此接口的类/类。因此,它为[ProtoInclude(1,typeof(MyClass))]提供了编译时错误。我尝试使用[ProtoInclude(int tag,string KownTypeName)]如下:
[ProtoContract]
[ProtoInclude(1, "MyClass")]
public interface IMyClass
{
int GetId();
string GetName();
}
但是,这会在行
处抛出“对象引用未设置为对象的实例”异常Serializer.Serialize(stream, myDict);
其中Dictionary myDict = new Dictionary(int,IMyClass)(); 在这种情况下,请让我知道如何使用ProtoInclude,以便在字典/列表中序列化接口类型。
答案 0 :(得分:4)
由于它不知道从哪里获取MyClass
,因此您应该为您的班级使用Type.AssemblyQualifiedName值。
以下是一些示例代码:
namespace Alpha
{
[ProtoContract]
[ProtoInclude(1, "Bravo.Implementation, BravoAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")]
//[ProtoInclude(1, "Bravo.Implementation")] // this likely only works because they're in the same file
public class PublicInterface
{
}
}
namespace Bravo
{
public class Implementation : Alpha.PublicInterface
{
}
public class Tests
{
[Test]
public void X()
{
// no real tests; just testing that it runs without exceptions
Console.WriteLine(typeof(Implementation).AssemblyQualifiedName);
using (var stream = new MemoryStream())
{
Serializer.Serialize(stream, new Implementation());
}
}
}
}
答案 1 :(得分:2)
Austin是正确的(我相信):使用程序集限定名称(作为字符串)应解决此问题。
在v2中,存在另一个选项:您可以在运行时而不是通过属性执行映射:
RuntimeTypeModel.Default[typeof(PulicInterface)]
.AddSubType(1, typeof(Implementation));
如果你的“app”层知道这两种类型,或者可以通过一些自定义配置/反射过程来完成,那么可以通过静态代码。