3

I use reflection find all the Classes in my project that Inherit from Packet.Base

Each of these classes has ProtoBuf attributes applied.

I've just experienced Protobuf.net Exception - Timeout while inspecting metadata my project and want to implement the PrepareSerializer without having to go through and add all the different class types in there.

Is there a simple way that I can dynamically prepare the classes given that I have the type from reflection without needing to call

ProtoBuf.Serializer.PrepareSerializer(Of Instruction)()
ProtoBuf.Serializer.PrepareSerializer(Of NoOperation)()

or adding a

Public MustOverride Sub Prepare()

to the base class and then in each class

Public Overrides Sub Prepare()
    Serializer.PrepareSerializer(Of TimeSynchronise)()
End Sub

This is the loading mechanism i'm using, a pretty simple reflection load.

Public Class CompatiblePackets
    Inherits Dictionary(Of Packet.PacketType, Base)

    Public Sub New()
        Dim theAssembly As Assembly = Assembly.GetExecutingAssembly
        For Each t As Type In theAssembly.GetTypes
            If t.BaseType Is GetType(Base) Then
                Dim p As Base = CType(t.Assembly.CreateInstance(t.FullName), Base)
                Me.Add(p.PacketTypeIndicator, p)
                End Try
            End If
        Next
    End Sub

    public sub Prepare
        ProtoBuf.Serializer.PrepareSerializer(t)()
    end sub 
Community
  • 1
  • 1
Paul Farry
  • 4,730
  • 2
  • 35
  • 61

1 Answers1

3

Yes, you can call that without generics:

RuntimeTypeModel.Default[type].CompileInPlace();

where:

  • RuntimeTypeModel.Default is the default type-model, which is what the Serializer.* methods use (v2 supports parallel independent type-models)
  • the [type] indexer performs and implicit Add if it is missing, using the default behaviours (attributes) - and thus does most of the metadata analysis
  • the CompileInPlace() does IL optimisation for the type

You can also try increasing RuntimeTypeModel.Default.MetadataTimeoutMilliseconds slightly.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • I'm using the portable version 2.0.0.668, I can't find CompileInPlace(), is there a new way to do this? Thanks. – pogorman Apr 10 '17 at 16:48
  • @pogorman portable is massively restricted in terms of meta-programming, so it uses the runtime model which is slower. For the "v major next", I'm investigating roslyn hooks for generation during build, which will be far more portable, but: it will target .net framework (4.6, iirc) and netstandard. So you'd need to be able to target one of those two (presumably the latter) to benefit, plus I don't have an ETA on that. Is targeting netstandard a possibility? – Marc Gravell Apr 10 '17 at 18:57
  • we use it a lot in portable libraries. Right now we are seeing "Timeout while inspecting metadata " errors on a mono system. The only time I've seen before is in xunit tests. I guess we could use the standard library and inject in to our portable libs.Net. netstandard is definitely possible, we use profile111 which is netstandard 1.1 – pogorman Apr 11 '17 at 18:43
  • @pogorman we need 1.3 to use runtime metaprogramming; 1.1 has the same lack of features as portable. I don't know exactly what targets will work for compile-time, as those bits are very early – Marc Gravell Apr 11 '17 at 19:54