Can't serialize generic type

大憨熊 提交于 2019-12-11 02:48:12

问题


I'm trying to serialize a generic type with protobuf-net, but protobuf-net says it can't serialize it.

As in:

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

returns true and

RuntimeTypeModel.Default.CanSerialize(typeof(string))

returns true, too. But

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

returns false. I guess I'm doing something wrong with how I add my MyGenericClass to the default runtimetype model. Since something like

RuntimeTypeModel.Default.CanSerialize(typeof(List<Document>))

returns true.

My current code for adding the generic class:

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

The error message says that there is no contract for the type I'm trying to serialize...which is obviously not true.

Here is an example demonstrating my problem and proofing that it should work:

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;
        }
    }
}

As a follow up (and to clarify my comments) let's take this code:

using System; using 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:


By doing:

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

You have configured the TestClass2<> type. Which is great, but... you never use that type. In fact, it cannot be used - Add should probably throw an error. You use TestClass<string> which to most intents and purposes is a completely separate Type instance.

I guess the logic here is that: a closed generic type should inherit its configuration from the generic type definition, if the generic type definition is configured. I can see the logic of that, but: that is not currently implemented, and like everything else would require specification, design, implementation, testing, support and documentation. Which takes time.

For today: if you want to work with TestClass2<string>, you should configure TestClass2<string>.

Note that when using attributes, attributes are inherently present on the closed types; so it is the case that TestClass1<string>.TestField has the [ProtoMember(1, DynamicType = true)] marker.

I suspect that if you do:

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

then it will work fine.



来源:https://stackoverflow.com/questions/24535269/cant-serialize-generic-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!