示例#1
0
        /// <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());
        }