C# 将字节数组烘焙为动态IL

C# 将字节数组烘焙为动态IL,c#,reflection,cil,reflection.emit,C#,Reflection,Cil,Reflection.emit,我正在通过发出IL来编写一个面向性能的数据反序列化程序。序列化数据为UTF8,字段表示为字符串 [FieldA]: 22 [FieldB]: 16 我已经编写了一个自定义读取器,它可以正确地标记序列化数据,并在遍历序列化数据时提供一个ReadOnlySpan 我希望有一个静态的、内联的反序列化器,它能够打包字段的字节签名,这样我就可以轻松地创建一个跳转表并设置适当的字段 非动态代码的外观: // byteSpan is a ReadOnlySpan<byte> containing

我正在通过发出IL来编写一个面向性能的数据反序列化程序。序列化数据为UTF8,字段表示为字符串

[FieldA]: 22
[FieldB]: 16
我已经编写了一个自定义读取器,它可以正确地标记序列化数据,并在遍历序列化数据时提供一个
ReadOnlySpan

我希望有一个静态的、内联的反序列化器,它能够打包字段的字节签名,这样我就可以轻松地创建一个跳转表并设置适当的字段

非动态代码的外观:

// 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();
...
//byteSpan是包含签名的只读span
var signatureA=Encoding.UTF8.GetBytes(“FieldA”);
var signatureB=Encoding.UTF8.GetBytes(“FieldB”);
if(字节序列相等(签名))
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 );
var fieldSignatures=GetTypeSignatures();//返回一个元组
var setFieldLabels=新列表();
字段签名中的foreach((字节[]签名,字段信息字段)
{
var setFieldLabel=il.DefineLabel();
添加(Tuple.Create(field,setFieldLabel));
il.Emit(OpCodes.Ldloc_1);//加载当前ReadOnlySpan
//此处内联加载字节[]签名
il.Emit(操作码调用,方法_SEQUENCEEQUAL);
il.Emit(操作码.Brtrue,setFieldLabel);
}
发射场设置器(设置场标签,参考il);
是否有一种方法可以将签名字节数组直接烘焙到我正在发射的IL中,以便它们成为委托的一部分


这些签名是在运行时基于类型信息生成的,因此在静态类中手动定义它们是不可行的。一种解决方法是定义一个新的动态
程序集
类型
,并将字节存储在其中,但如果可能的话,我希望避免这样做。

您可能需要做的是将一个签名字节数组(
byte[][
)数组作为隐藏的第一个参数传递给动态方法

您可以通过以下方式加载适当的字节数组:

// Load the first byte[][] signatures array argument
il.Emit( OpCodes.LdArg_0 );
// Load the index into the signatures array
il.Emit( OpCodes.Ldc_I4, signatureIndex );
// Fetch the signature byte[] element from the array
il.Emit( OpCodes.Ldelem_Ref );
然后,当您从dynamic方法创建委托时,可以使用接受目标对象的重载,该重载将成为(隐藏的)第一个参数:

var deserializerDelegate = dynamicMethod.CreateDelegate(typeof(YourDelegateType), signatures);

综上所述,请参阅我对上述问题的评论,即使用替代的签名查找算法,该算法可能比线性搜索更为优化,即使使用动态生成的IL。

因为您使用的是通过发射IL来提高性能,对字段签名执行线性搜索真的是最好的方法吗?似乎一个更优化的查找机制(即使在没有发出IL的情况下实现)可能比使用自定义IL执行线性查找更有效。至少看看C#编译器在您使用switch(stringvar)时生成的代码,它比您现在所做的要高效得多。我不熟悉任何其他搜索算法。。。对象字段总是通过它们的字符串名称(签名的来源)来标识。您是否想到了一种适用于此的算法?@Haus-仅使用内置的
字典
根据字段名查找setter委托可能比您在自定义IL中实现的线性搜索要高效得多。