protobuf-net's [ProtoInclude(1, "MyClass")] did not work
I am using protobuf-net v2 beta r431 for C# .net 4.0 application. In my application I have a Dictionary<int, IMyClass>
which i need to serialize. A class MyClass
implements IMyClass
interface. As per protobuf's documentations I wrote the code as under:
[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
}
However, as per my application's design, the interface is defined at a higher level (in a different project than the classes) and it is not possible to determine the class/classes that implements this interface at compile time. Hence, it gives compile time error for [ProtoInclude(1, typeof(MyClass))]. I tried to use [ProtoInclude(int tag, string KownTypeName)] as following:
[ProtoContract]
[ProtoInclude(1, "MyClass")]
public interface IMyClass
{
int GetId();
string GetName();
}
But, this th开发者_运维问答rew an "Object reference not set to instance of an object" exception at line
Serializer.Serialize(stream, myDict);
where Dictionary myDict = new Dictionary(int, IMyClass)(); Please let me know how to use ProtoInclude in this case so as to serialize interface type inside dictionary / list.
Since it will have no idea where to get your MyClass
, you should probably use the Type.AssemblyQualifiedName value for your class.
Here's some example code:
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());
}
}
}
}
Austin is correct (I believe): using an assembly-qualified name (as a string) should resolve this.
In v2, an additional option exists: you can perform the mapping at runtime instead of via attributes:
RuntimeTypeModel.Default[typeof(PulicInterface)]
.AddSubType(1, typeof(Implementation));
This could be be through static code if your "app" tier knows about both types, or could be done via some custom configuration / reflection process.
精彩评论