Ответ 1
Вам нужно будет использовать инфраструктуру в пространстве имен System.Reflection.Emit. В частности, вы должны посмотреть docs для MethodBuilder.CreateMethodBody
, который принимает массив байтов, представляющий инструкции MSIL. Здесь есть полный пример, но ниже приведен короткий фрагмент его использования. Здесь я также создам делегат для динамического метода.
Отмечу, что это поддерживается только очень ограниченным образом, который вызывается в документах:
В настоящее время это не полностью поддерживается. Пользователь не может предоставить местоположение исправлений фишек и обработчиков исключений.
Проблема заключается в том, что токены метаданных, используемые в IL для ссылочных типов, методов, строковых литералов и т.д., разрешаются на уровне модуля. Таким образом, IL не полностью переносится в том смысле, что вы не можете взять произвольный, необработанный IL из метода в одном модуле и просто отбросить его в другой метод в другом модуле. В новом модуле нужны жетоны метаданных. Однако, если вы знаете, что ваш IL не содержит токенов метаданных, вы можете это сделать, но это сильно ограничивает то, что вы можете сделать с этим. (HT: svick, Саймон Свенссон)
class Program
{
static void Main(string[] args)
{
// opcodes for pushing two arguments to the stack, adding, and returning the result.
byte[] ilcodes = { 0x02, 0x03, 0x58, 0x2A };
var method = CreateFromILBytes(ilcodes);
Console.WriteLine(method(2, 3));
}
private static Func<int, int, int> CreateFromILBytes(byte[] bytes)
{
var asmName = new AssemblyName("DynamicAssembly");
var asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave);
var module = asmBuilder.DefineDynamicModule("DynamicModule");
var typeBuilder = module.DefineType("DynamicType");
var method = typeBuilder.DefineMethod("DynamicMethod",
MethodAttributes.Public | MethodAttributes.Static,
typeof(int),
new[] { typeof(int), typeof(int) });
method.CreateMethodBody(bytes, bytes.Length);
var type = typeBuilder.CreateType();
return (Func<int, int, int>)type.GetMethod("DynamicMethod").CreateDelegate(typeof(Func<int, int, int>));
}
}
Обратите внимание на использование опции RunAndSave
. Это позволит сохранить динамическую сборку на диск во временном месте. Может быть более желательно использовать RunAndCollect
, который генерирует сборку только в памяти и позволяет собирать ее позже, когда все ссылки на нее мертвы. Однако есть некоторые предостережения для так называемых коллекционных сборок, подробные здесь.