我有一个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方法按照所述here in docs
导入以下是完整代码:
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"");
}
}
}"
}
任何帮助都会得到应用