无法序列化泛型类型

时间:2014-07-02 15:32:42

标签: c# generics protobuf-net

我尝试使用protobuf-net序列化泛型类型,但protobuf-net表示它无法对其进行序列化。

如:

RuntimeTypeModel.Default.CanSerialize(typeof(MyGenericClass<>))

返回true和

RuntimeTypeModel.Default.CanSerialize(typeof(string))

也会返回true。但

RuntimeTypeModel.Default.CanSerialize(typeof(MyGenericClass<string>)) //--> applies to all types that would return true when directly serialized as shown above for the string type

返回false。我想我在将MyGenericClass添加到默认运行时类型模型方面做错了。因为像

这样的东西
RuntimeTypeModel.Default.CanSerialize(typeof(List<Document>))

返回true。

我目前添加通用类的代码:

var addedGenericType = RuntimeTypeModel.Default.Add(typeof(MyGenericClass<>), false);
addedGenericType.Add("Field1", "GenericField");

错误消息显示我没有尝试序列化的类型的合同......这显然不是真的。

这是一个展示我的问题并证明它应该有效的例子:

using System;
using ProtoBuf;

namespace TestApplication
{
    [ProtoContract]
    public class TestClass<T>
    {
        [ProtoMember(1, DynamicType = true)]
        public T TestField { get; set; }

    }

    public class TestClass2<T>
    {
        public T TestField { get; set; }
    }

    public class Tester
    {
        public void Test()
        {
            DefineSecondClass();
            bool testResult = ProtoBuf.Meta.RuntimeTypeModel.Default.CanSerialize(typeof(TestClass<string>));            
            bool testResult2 = ProtoBuf.Meta.RuntimeTypeModel.Default.CanSerialize(typeof(TestClass2<string>));
            bool testResult3 = ProtoBuf.Meta.RuntimeTypeModel.Default.CanSerialize(typeof(TestClass2<>));
            Console.WriteLine(testResult); // returns true
            Console.WriteLine(testResult2); // returns false
            Console.WriteLine(testResult3); // returns true
        }

        private void DefineSecondClass()
        {
            var type = ProtoBuf.Meta.RuntimeTypeModel.Default.Add(typeof(TestClass2<>), false);
            type.AddField(1, "TestField");
            type[1].DynamicType = true;
        }
    }
}

作为跟进(并澄清我的评论),请使用此代码:

使用System;     使用ProtoBuf;

namespace TestApplication
{        

    public class TestClass<T>
    {
        public T TestField { get; set; }
    }

    public class ComplexType
    {
        public string SomeFieldA{get; set;}
        public int SomeFieldB{get; set;}
    }

    public class Tester
    {
        public void Test()
        {
            DefineComplexType();
            // how to add the type TestClass<ComplexType> to the RuntimeTypeModel without calling
            // DefineComplexType() again?
        }

        private void DefineComplexType()
        {
            var type = ProtoBuf.Meta.RuntimeTypeModel.Default.Add(typeof(ComplexType), false);
            type.AddField(1, "SomeFieldA");
        }
    }
}

1 个答案:

答案 0 :(得分:2)

通过做:

var type = ProtoBuf.Meta.RuntimeTypeModel.Default.Add(
    typeof(TestClass2<>), false);
type.AddField(1, "TestField");
type[1].DynamicType = true;

您已配置TestClass2<>类型。哪个好,但是......你永远不会使用那种类型。实际上,它无法使用 - Add应该抛出错误。您使用TestClass<string>对于大多数意图和目的而言,它是一个完全独立的Type实例。

我想这里的逻辑是:如果配置了泛型类型定义,则封闭泛型类型应该从泛型类型定义继承其配置。我可以看到它的逻辑,但是:当前没有实现,并且其他一切都需要规范,设计,实现,测试,支持和文档。这需要时间。

今天:如果你想使用TestClass2<string>,你应该配置 TestClass2<string>

请注意,使用属性时,属性本身就存在于封闭类型上;因此,TestClass1<string>.TestField具有[ProtoMember(1, DynamicType = true)]标记。

我怀疑如果你这样做:

private void DefineSecondClass()
{
    var type = ProtoBuf.Meta.RuntimeTypeModel.Default.Add(
        typeof(TestClass2<string>), false);
    type.AddField(1, "TestField");
    type[1].DynamicType = true;
}

然后它会正常工作。