Импорт метода завершается ошибкой с помощью Mono.Cecil
У меня есть исходный код класса TestClass, хранящийся в виде строки, и мне нужно создать DLL с другим классом, содержащим код из одного метода TestClass. Вот TestClass, хранящийся в виде строки:
namespace Test
{
public static class TestClass
{
public static void TestMethod()
{
System.Console.WriteLine("something");
}
}
}
Я компилирую этот код, используя CSharpCodeProvider, затем с помощью Mono.Cecil создаю новую сборку, создаю новый тип, новый метод и копирую (фактически клонирую) в него инструкции скомпилированного метода. Что не работает, так это на этапе записи сборки на диск, выдается исключение:
Необработанное исключение типа "System.ArgumentException" возникло в Mono.Cecil.dll Дополнительная информация: Элемент "System.Void System.Console::WriteLine(System.String)" объявлен в другом модуле и должен быть импортирован.
Метод Console.WriteLine импортируется, как указано здесь в документации
Вот полный код:
class Program
{
static void Main()
{
var assemblyDefinition = AssemblyDefinition.CreateAssembly(
new AssemblyNameDefinition("Test", new Version(1, 0)), "module", ModuleKind.Console);
var type = new TypeDefinition("Test", "TestClass", TypeAttributes.Public);
var methodDefinition = new MethodDefinition(
"TestMethod",
MethodAttributes.Static | MethodAttributes.Public,
assemblyDefinition.MainModule.Import(typeof(void)));
type.Methods.Add(methodDefinition);
assemblyDefinition.MainModule.Types.Add(typeDefinition);
AddMethodBody(methodDefinition);
assemblyDefinition.Write("generated.dll");
}
private static void AddMethodBody(MethodDefinition methodDefinition)
{
var parameters = new CompilerParameters();
parameters.ReferencedAssemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies().Select(x => x.Location).ToArray());
var result = _compiler.CompileAssemblyFromSource(parameters, TestClassSource);
var compiledAssembly = AssemblyDefinition.ReadAssemblly(result.CompiledAssembly.Location);
var type = compiledAssembly.MainModule.Types.First(x => x.FullName == "Test.TestClass");
var method = type.Methods.First(x => x.Name == "TestMethod");
var instructions = method.Body.Instructions;
var ctorInfo = typeof(Instruction).GetConstructor(
BindingFlags.NonPublic | BindingFlags.Instance, null,
new[] { typeof(OpCode, typeof(object) }, null);
foreach(var inst in instructions)
{
var newInstruction = (Instruction)ctorInfo.Invoke(new[] {inst.OpCode, inst.Operand});
methodDefinition.Body.Instructions.Add(newInstruction);
}
var il = methodDefinition.Body.GetILProcessor();
var ldstr = il.Create(OpCodes.Ldstr, methodDefinition.Name);
var class = il.Create(OpCodes.Call,
methodDefinition.Module.Import(typeof(Console).GetMethod("WriteLine", new[] { typeof(string) })));
il.InsertBefore(methodDefinition.Body.Instructions[0], ldstr);
il.InsertAfter(methodDefinition.Body.Instructions[0], call);
}
private static string TestClassSource =
@"
namespace Test
{
public static class TestClass
{
public static void TestMethod()
{
System.Console.WriteLine(""abc"");
}
}
}"
}
Любая помощь будет оценена