I have a piece of code that is supposed to use Linq Expressions to put together a "compiled at run time" lambda function to persist events to a stream.
(This is to allow the function to be swapped out by injection if you want to use a different serialisation technology)
The code is:-
Public Function CreateDefaultSaveToStreamFunction(Of TEvent As {New, IEvent})() As Func(Of TEvent, System.IO.Stream, Long)
Dim valueParameter As ParameterExpression =
Expression.Parameter(GetType(TEvent), "eventToSerialise")
Dim streamParameter As ParameterExpression =
Expression.Parameter(GetType(System.IO.Stream), "stream")
Dim sequenceParameter As ParameterExpression =
Expression.Variable(GetType(Long), "sequence")
Dim innerBlockExpressions As New List(Of Expression)()
innerBlockExpressions.Add(Expression.Assign(sequenceParameter,
Expression.[New](GetType(Long))))
Dim binaryFormatterParameter As ParameterExpression =
Expression.Variable(GetType(System.Runtime.Serialization.Formatters.Binary.BinaryFormatter), "bf")
innerBlockExpressions.Add(Expression.Assign(binaryFormatterParameter,
Expression.[New](GetType(System.Runtime.Serialization.Formatters.Binary.BinaryFormatter))))
Dim serialiseMethod As MethodInfo = GetType(System.Runtime.Serialization.Formatters.Binary.BinaryFormatter).GetMethod("Serialize", {GetType(System.IO.Stream), GetType(Object)})
innerBlockExpressions.Add(
Expression.Call(binaryFormatterParameter, serialiseMethod, {streamParameter, valueParameter})
)
innerBlockExpressions.Add(Expression.Assign(sequenceParameter,
Expression.PropertyOrField(streamParameter, "Position")
)
)
innerBlockExpressions.Add(sequenceParameter)
Dim innerBlock As BlockExpression = Expression.Block({valueParameter, streamParameter, sequenceParameter, binaryFormatterParameter},
innerBlockExpressions.AsEnumerable())
Dim toStreamBody As BlockExpression = Expression.Block(
New ParameterExpression() {valueParameter, streamParameter},
innerBlock)
Dim retLambda As LambdaExpression = Expressions.Expression(Of EventSerializer(Of TEvent).SaveToStream).Lambda(toStreamBody, {valueParameter, streamParameter})
Dim retDeletage = retLambda.Compile()
Return retDeletage
End Function
When I run this for a given event type it creates a lambda expression like:-
.Block(
CQRSAzure.EventSourcing.UnitTest.Mocking.MockEventTypeTwo $eventToSerialise,
System.IO.Stream $stream) {
.Block(
CQRSAzure.EventSourcing.UnitTest.Mocking.MockEventTypeTwo $eventToSerialise,
System.IO.Stream $stream,
System.Int64 $sequence,
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter $bf) {
$sequence = .New System.Int64();
$bf = .New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
.Call $bf.Serialize(
$stream,
$eventToSerialise);
$sequence = $stream.Position;
$sequence
}
}
When I call this Lambda function it does return the stream position (in the variable "sequence") but the stream itself is not written back to the variable I pass in.
What I have tried:
Tried changing around the method signature
{Method = {Int64 lambda_method(System.Runtime.CompilerServices.Closure, CQRSAzure.EventSourcing.UnitTest.Mocking.MockEventTypeTwo, System.IO.Stream)}}
This shows the stream is being passed in - and the length is also being set..?