Фон:
Я хочу определить несколько методов static
в С# и сгенерировать IL-код как массив байтов из одного из этих методов, выбранных во время выполнения (на клиенте) и отправить массив байтов по сети на другой компьютер (сервер) где он должен быть выполнен после повторного генерации кода IL из массива байтов.
Моя попытка: (POC)
public static class Experiment
{
public static int Multiply(int a, int b)
{
Console.WriteLine("Arguments ({0}, {1})", a, b);
return a * b;
}
}
И затем я получаю код IL тела метода, как:
BindingFlags flags = BindingFlags.Public | BindingFlags.Static;
MethodInfo meth = typeof(Experiment).GetMethod("Multiply", flags);
byte[] il = meth.GetMethodBody().GetILAsByteArray();
До сих пор я ничего не создавал динамически. Но у меня IL-код как массив байтов, и я хочу создать сборку, затем модуль в ней, затем тип, затем метод - все динамически. При создании тела метода динамически созданного метода я использую код IL, который я получил, используя отражение в приведенном выше коде.
Код генерации кода выглядит следующим образом:
AppDomain domain = AppDomain.CurrentDomain;
AssemblyName aname = new AssemblyName("MyDLL");
AssemblyBuilder assemBuilder = domain.DefineDynamicAssembly(
aname,
AssemblyBuilderAccess.Run);
ModuleBuilder modBuilder = assemBuilder.DefineDynamicModule("MainModule");
TypeBuilder tb = modBuilder.DefineType("MyType",
TypeAttributes.Public | TypeAttributes.Class);
MethodBuilder mb = tb.DefineMethod("MyMethod",
MethodAttributes.Static | MethodAttributes.Public,
CallingConventions.Standard,
typeof(int), // Return type
new[] { typeof(int), typeof(int) }); // Parameter types
mb.DefineParameter(1, ParameterAttributes.None, "value1"); // Assign name
mb.DefineParameter(2, ParameterAttributes.None, "value2"); // Assign name
//using the IL code to generate the method body
mb.CreateMethodBody(il, il.Count());
Type realType = tb.CreateType();
var meth = realType.GetMethod("MyMethod");
try
{
object result = meth.Invoke(null, new object[] { 10, 9878 });
Console.WriteLine(result); //should print 98780 (i.e 10 * 9878)
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Но вместо печати 98780
в окне вывода, он выдает исключение, говорящее
System.Reflection.TargetInvocationException: Исключение выбрано целевым объектом вызова. --- > System.TypeLoadException: Не удалось загрузить тип Invalid_Token.0x0100001E из сборки 'MyDLL, Version = 0.0.0.0, Culture = neutral, PublicKeyToken = null'.
в MyType.MyMethod(Int32 value1, Int32 value2) [...]
Пожалуйста, помогите мне разобраться с причиной ошибки и как ее исправить.