问题描述
我最近一直在玩 Mono.Cecil,主要是为了我计划编写的编译器。我首先尝试了 this answer 中的代码。代码如下:
var myHelloWorldApp = AssemblyDeFinition.CreateAssembly(
new AssemblyNameDeFinition("HelloWorld",new Version(1,0)),"HelloWorld",ModuleKind.Console);
var module = myHelloWorldApp.MainModule;
// create the program type and add it to the module
var programType = new TypeDeFinition("HelloWorld","Program",Mono.Cecil.TypeAttributes.Class | Mono.Cecil.TypeAttributes.Public,module.TypeSystem.Object);
module.Types.Add(programType);
// add an empty constructor
var ctor = new MethodDeFinition(".ctor",Mono.Cecil.MethodAttributes.Public | Mono.Cecil.MethodAttributes.HideBySig
| Mono.Cecil.MethodAttributes.SpecialName | Mono.Cecil.MethodAttributes.RTSpecialName,module.TypeSystem.Void);
// create the constructor's method body
var il = ctor.Body.GetILProcessor();
il.Append(il.Create(OpCodes.Ldarg_0));
// call the base constructor
il.Append(il.Create(OpCodes.Call,module.ImportReference(typeof(object).GetConstructor(Array.Empty<Type>()))));
il.Append(il.Create(OpCodes.nop));
il.Append(il.Create(OpCodes.Ret));
programType.Methods.Add(ctor);
// define the 'Main' method and add it to 'Program'
var mainMethod = new MethodDeFinition("Main",Mono.Cecil.MethodAttributes.Public | Mono.Cecil.MethodAttributes.Static,module.TypeSystem.Void);
programType.Methods.Add(mainMethod);
// add the 'args' parameter
var argsParameter = new ParameterDeFinition("args",Mono.Cecil.Parameterattributes.None,module.ImportReference(typeof(string[])));
mainMethod.Parameters.Add(argsParameter);
// create the method body
il = mainMethod.Body.GetILProcessor();
il.Append(il.Create(OpCodes.nop));
il.Append(il.Create(OpCodes.Ldstr,"Hello World"));
var writeLineMethod = il.Create(OpCodes.Call,module.ImportReference(typeof(Console).getmethod("WriteLine",new[] { typeof(string) })));
// call the method
il.Append(writeLineMethod);
il.Append(il.Create(OpCodes.nop));
il.Append(il.Create(OpCodes.Ret));
// set the entry point and save the module
myHelloWorldApp.EntryPoint = mainMethod;
myHelloWorldApp.Write("HelloWorld.exe");
请注意,我将 module.Import
更改为 module.ImportReference
,因为前者显然已过时。
我将其放入一个 .NET 5 项目中,并创建了一个 HelloWorld.exe
。由于我在 macOS 上,我尝试使用单声道运行 exe:
mono HelloWorld.exe
它打印了“Hello World”。到目前为止一切顺利。
当我将这个 HelloWorld.exe
发送给使用 Windows 计算机的朋友时,问题就出现了。当他这样运行时(注意他在 Windows 上没有单声道):
.\HelloWorld.exe
未处理的异常:System.IO.FileNotFoundException:无法加载文件或程序集“System.Console,版本=5.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a”或其依赖项之一。系统找不到指定的文件。
在HelloWorld.Program.Main(String[] args)
我尝试查找错误消息,但所有结果都无法找到System.Runtime
。 System.Console
甚至是一个程序集吗?不是上课吗?
如何在 Windows 机器上运行 exe? 代码中有什么我需要更改的地方吗?还是Windows机器需要安装什么东西?我认为这可能与我使用 .NET 5 有关,但 Windows 机器只有 .NET Framework。
问题到此结束,以下是我的发现:
作为“对照组”,我尝试做最简单的Hello World C#程序:
class Program {
public static void Main() {
System.Console.WriteLine("Hello World");
}
}
在 macOS(即 Mono 编译器)上使用 csc
编译它,并在 Windows 上运行输出 exe。这是有效的,所以我反汇编(使用 dotnet-ildasm
)Mono.Cecil 生成的 exe 和 csc
生成的 exe,并比较它们。我发现的最有趣的区别是“损坏的”exe 中有这些额外的程序集引用:
.assembly extern System.Private.CoreLib
{
.publickeytoken = ( 7C EC 85 D7 BE A7 79 8E ) // ....y.
.ver 5:0:0:0
}
.assembly extern System.Console
{
.publickeytoken = ( B0 3F 5F 7F 11 D5 0A 3A ) // .._.....
.ver 5:0:0:0
}
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)