Why don't some Built-in types work when I compile typeModel?

Viewed 65

When I compile Type model dictionary stops working.

    [Test]
    public void TestCompileSerialization()
    {
        var data = new Dictionary<int, int>();
        data[1] = 1;

        var typeModel = TypeModel.Create();
        var compiledTypeModel = typeModel.Compile();

        using (var memory = new MemoryStream())
        {
            compiledTypeModel.Serialize(memory, data);
        }
    }

This test throws

Type is not expected, and no contract can be inferred: System.Collections.Generic.KeyValuePair`2[[System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Int32, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]

Do I need to add every dictionary that I might want to serialize to TypeModel or there are some other ways?

BTW I don't get why do I have to make everything public when I want to precompile serializers?

1 Answers

Yes, when you are creating your own type model, you need to tell it what to include in advance - otherwise it won't know what to support. Ideally this includes all types that you would serialize as root types, so: if you're going to be serializing a dictionary: tell it. Internally, protobuf-net v2 doesn't actually special-case dictionaries - it sees them as a list-like sequence of a type (KeyValuePair<TKey, TValue>) that happens to look a lot like a type it can guess about as being a "tuple"; protobuf-net v3 does know more about dictionaries, but... you're still better off telling it in advance.

BTW I don't get why do I have to make everything public when I want to precompile serializers?

There are two types of precompilation; perhaps you actually just want CompileInPlace() (rather than Compile()), which retains the existing RuntimeTypeModel, but uses IL-emit under the covers to create lightweight shim methods to do the work; when using this approach, it is possible to bypass accessibility verification checks, allowing me to access non-public anything; however, when you use Compile(), you are creating real types in a real assembly (just: in memory), and when you do that: you cannot bypass accessibility checks (and a few other verification checks); this means I am subject to the same rules as you would be in, say, the C# compiler: if it isn't public, I can't touch it.

Related