protobuf-net 的 [ProtoInclude(1, "MyClass")] 不起作用

Posted

技术标签:

【中文标题】protobuf-net 的 [ProtoInclude(1, "MyClass")] 不起作用【英文标题】:protobuf-net's [ProtoInclude(1, "MyClass")] did not work 【发布时间】:2011-09-28 15:29:27 【问题描述】:

我将 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 来序列化字典/列表中的接口类型。

【问题讨论】:

【参考方案1】:

由于它不知道从哪里获取您的 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());
            
        
    

【讨论】:

话虽如此,您应该等着看 Marc Gravell 的反应,因为它肯定会是解决您的问题的方法。 在 v1 这将是“方式”。在 v2 中,它是两种方式之一。不过,一个很好的答案 - 节省了我很多打字时间。【参考方案2】:

Austin 是正确的(我相信):使用程序集限定名称(作为字符串)应该可以解决此问题。

在 v2 中,存在一个附加选项:您可以在运行时执行映射,而不是通过属性:

RuntimeTypeModel.Default[typeof(PulicInterface)]
    .AddSubType(1, typeof(Implementation));

如果您的“应用”层知道这两种类型,这可以通过静态代码实现,或者可以通过一些自定义配置/反射过程来完成。

【讨论】:

以上是关于protobuf-net 的 [ProtoInclude(1, "MyClass")] 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Protobuf-net:嵌套的 IEnumerable 对象

用于继承的 Protobuf-net .proto 文件生成

带有 Protobuf-net 的端点行为配置 WCF

使用protobuf-net继承时如何选择字段号?

protobuf-net:如何注释派生类型的属性?

仅在 ProtoBuf-net 中序列化基类