Я пишу ориентированный на производительность десериализатор данных, испуская IL. Сериализованные данные UTF8
, а поля обозначены как строки.
[FieldA]: 22
[FieldB]: 16
Я уже написал специальную программу чтения, которая должным образом токенизирует сериализованные данные и предоставляет ReadOnlySpan<byte>
при пошаговом выполнении сериализованных данных.
Мне бы хотелось иметь статический встроенный десериализатор, который мог бы иметь упакованные байтовые подписи полей, чтобы я мог легко создать таблицу переходов и установить соответствующие поля.
Как может выглядеть не динамический код:
// byteSpan is a ReadOnlySpan<byte> containing the signature
var signatureA = Encoding.UTF8.GetBytes( "FieldA" );
var signatureB = Encoding.UTF8.GetBytes( "FieldB" );
if( byteSpan.SequenceEqual( signatureA ) )
DoSomething();
else if ( byteSpan.SequenceEqual( signatureB ) )
DoSomething();
...
Как создается таблица переходов:
var fieldSignatures = GetTypeSignatures<T>(); // Returns a Tuple<byte[], FieldInfo>
var setFieldLabels = new List<Tuple<FieldInfo, Label>>();
foreach( (byte[] signature, FieldInfo field) in fieldSignatures )
{
var setFieldLabel = il.DefineLabel();
setFieldLabels.Add( Tuple.Create( field, setFieldLabel ) );
il.Emit( OpCodes.Ldloc_1 ); // Load the current ReadOnlySpan<byte>
// Inline load byte[] signature here
il.Emit( OpCodes.Call, METHOD_SEQUENCEEQUAL );
il.Emit( OpCodes.Brtrue, setFieldLabel );
}
EmitFieldSetters( setFieldLabels, ref il );
Есть ли способ, которым я могу испечь массивы байтов подписи непосредственно в IL, который я излучаю, чтобы они были частью делегата?
Эти сигнатуры генерируются во время выполнения на основе информации о типе, поэтому их определение вручную в статическом классе невозможно. Обходным путем может быть определение новых динамических Assembly
и Type
и сохранение там байтов, но я хотел бы избежать необходимости делать это, если это возможно.