/// <summary> /// Builds a serialization function for the Confluent wire format. /// </summary> /// <param name="id"> /// A schema ID to include in each serialized payload. /// </param> /// <param name="schema"> /// The schema to build the Avro serializer from. /// </param> /// <returns> /// A function configured to serialize <typeparamref name="T" /> to an array of bytes. /// </returns> protected virtual Func <T, byte[]> Build(int id, Abstract.Schema schema) { var header = new byte[5]; Array.Copy(BitConverter.GetBytes(id), 0, header, 1, 4); if (BitConverter.IsLittleEndian) { Array.Reverse(header, 1, 4); } var inner = SerializerBuilder.BuildDelegateExpression <T>(schema); var stream = Expression.Parameter(typeof(MemoryStream)); var value = inner.Parameters[0]; var streamConstructor = typeof(MemoryStream) .GetConstructor(Type.EmptyTypes); var writerConstructor = inner.Parameters[1].Type .GetConstructor(new[] { typeof(Stream) }); var dispose = typeof(IDisposable) .GetMethod(nameof(IDisposable.Dispose), Type.EmptyTypes); var toArray = typeof(MemoryStream) .GetMethod(nameof(MemoryStream.ToArray), Type.EmptyTypes); var write = typeof(Stream) .GetMethod(nameof(Stream.Write), new[] { typeof(byte[]), typeof(int), typeof(int) }); if (schema is BytesSchema) { inner = new WireFormatBytesSerializerRewriter(stream) .VisitAndConvert(inner, GetType().Name); } var writer = Expression.Block( new[] { stream }, Expression.Assign(stream, Expression.New(streamConstructor)), Expression.TryFinally( Expression.Block( Expression.Call( stream, write, Expression.Constant(header), Expression.Constant(0), Expression.Constant(header.Length)), Expression.Invoke( inner, value, Expression.New(writerConstructor, stream))), Expression.Call(stream, dispose)), Expression.Call(stream, toArray)); return(Expression.Lambda <Func <T, byte[]> >(writer, value).Compile()); }