问题
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