Если я возьму следующий метод:
public static int Multiply(int a, int b)
{
return a * b;
}
скомпилируйте его в режиме Release и используйте в своем коде, все работает нормально. И если я проверю массив il
, он содержит 4 байта, которые в точности соответствуют четырем инструкциям из ответа Джона (ldarg.0, ldarg.1, mul, ret).
Если я скомпилирую его в режиме отладки, код будет 9 байтов. А в Reflector это выглядит так:
.method public hidebysig static int32 Multiply(int32 a, int32 b) cil managed
{
.maxstack 2
.locals init (
[0] int32 CS$1$0000)
L_0000: nop
L_0001: ldarg.0
L_0002: ldarg.1
L_0003: mul
L_0004: stloc.0
L_0005: br.s L_0007
L_0007: ldloc.0
L_0008: ret
}
Проблемной частью является локальная переменная. Если вы просто копируете байты инструкции, вы отправляете инструкцию, которая использует локальную переменную, но никогда не объявляете ее.
Если бы вы использовали ILGenerator
, вы могли бы использовать DeclareLocal()
. Кажется, вы сможете установить локальные переменные, используя MethodBuilder.SetMethodBody()
в .Net 4.5 (в VS 11 DP у меня работает следующее):
var module = typeof(Experiment).Module;
mb.SetMethodBody(il, methodBody.MaxStackSize,
module.ResolveSignature(methodBody.LocalSignatureMetadataToken),
null, null);
Но я не нашел способа сделать это в .Net 4, кроме как с помощью отражения задать частное поле MethodBuilder
, которое содержит локальные переменные, после вызова CreateMethodBody()
:
typeof(MethodBuilder)
.GetField("m_localSignature", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(mb, module.ResolveSignature(methodBody.LocalSignatureMetadataToken));
Относительно исходной ошибки: Типы и методы из других сборок (например, System.Console
и System.Console.WriteLine
) ссылаются с помощью токенов. И эти токены отличаются от сборки к сборке. Это означает, что код для вызова Console.WriteLine()
в одной сборке будет отличаться от кода для вызова того же метода в другой сборке, если вы посмотрите на байты инструкции.
Это означает, что вам действительно нужно понять, что означают байты IL, и заменить все токены, которые ссылаются на типы, методы и т. Д., На токены, действительные в сборке, которую вы строите.