Передайте system.io.stream по ссылке на expression.parameter
У меня есть фрагмент кода, который должен использовать выражения Linq для создания "скомпилированной во время выполнения" лямбда-функции для сохранения событий в потоке.
(Это делается для того, чтобы функция могла быть заменена инъекцией, если вы хотите использовать другую технологию сериализации)
Код таков:-
Public Function CreateDefaultSaveToStreamFunction(Of TEvent As {New, IEvent})() As Func(Of TEvent, System.IO.Stream, Long) 'otherwise build the function by reflection Dim valueParameter As ParameterExpression = Expression.Parameter(GetType(TEvent), "eventToSerialise") 'Type to be populated... 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)() 'Dim sequence As Long innerBlockExpressions.Add(Expression.Assign(sequenceParameter, Expression.[New](GetType(Long)))) 'Dim bf As New BinaryFormatter() 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)))) 'Public Sub Serialize(serializationStream As Stream, graph As Object) 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}) ) 'sequence = streamParameter.Position innerBlockExpressions.Add(Expression.Assign(sequenceParameter, Expression.PropertyOrField(streamParameter, "Position") ) ) 'Return sequenceParameter 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
Когда я запускаю это для данного типа события, оно создает лямбда-выражение, например:-
.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 } }
Когда я вызываю эту лямбда-функцию, она возвращает позицию потока (в переменной "последовательность"), но сам поток не записывается обратно в переменную, которую я передаю.
Что я уже пробовал:
Попробовал изменить сигнатуру метода
{Method = {Int64 lambda_method(System.Runtime.CompilerServices.Closure, CQRSAzure.EventSourcing.UnitTest.Mocking.MockEventTypeTwo, System.IO.Stream)}}
Это показывает, что поток передается - и длина также устанавливается..?