如何在Mono MSC C#编译器中添加NuGet程序集引用?
问题:嵌入Mono运行C#脚本时程序集引用失败
编译C#脚本时出现以下程序集缺失错误:
C:\Users\user\Documents\GitHub\callCsharp-fromCPP\CMonoTest\Mp3ToSpeech.cs(1,14): error CS0234: The type or namespace name `Speech' does not exist in the namespace `System'. Are you missing an assembly reference? C:\Users\user\Documents\GitHub\callCsharp-fromCPP\CMonoTest\Mp3ToSpeech.cs(6,7): error CS0246: The type or namespace name `NAudio' could not be found. Are you missing an assembly reference? C:\Users\user\Documents\GitHub\callCsharp-fromCPP\CMonoTest\SeleniumWebdriver.cs(1,7): error CS0246: The type or namespace name `OpenQA' could not be found. Are you missing an assembly reference? ...
用于嵌入Mono的C++代码如下:
#include <windows.h> #include <mono/jit/jit.h> #include <mono/metadata/assembly.h> #include <mono/metadata/debug-helpers.h> #include <cstdlib> #include <string> #include <iostream> #include <sstream> #include <direct.h> #include <filesystem> #pragma comment(lib, "mono-2.0-boehm.lib") // replaced from mono-2.0.lib #pragma comment(lib, "mono-2.0-sgen.lib") // It is new with GC code library GC from Gnu Compilication #pragma comment(lib , "MonoPosixHelper.lib") std::string get_working_path() { char temp[260]; // max windows path length return (_getcwd(temp, sizeof(temp)) ? std::string(temp) : std::string("")); } int main(int argc, char* argv[]) { #pragma region Load and compile the script std::string Mp3Path = std::filesystem::path(get_working_path()).parent_path().string() + R"(\CMonoTest\ChromeDriverInstaller.cs )"; std::string ProgramPath = std::filesystem::path(get_working_path()).parent_path().string() + R"(\CMonoTest\Program.cs )"; std::string ChromeInstPath = std::filesystem::path(get_working_path()).parent_path().string() + R"(\CMonoTest\Mp3ToSpeech.cs )"; std::string SeleniumWebPath = std::filesystem::path(get_working_path()).parent_path().string() + R"(\CMonoTest\SeleniumWebdriver.cs )"; //C:\Users\user\.nuget\packages\dotnetseleniumextras.waithelpers\3.11.0\lib\net45\SeleniumExtras.WaitHelpers.dll //C:\Users\user\.nuget\packages\naudio\2.1.0\lib\net6.0\NAudio.dll //C:\Users\user\.nuget\packages\selenium.support\4.4.0\lib\net5.0\WebDriver.Support.dll //C:\Users\user\.nuget\packages\selenium.webdriver\4.4.0\lib\net5.0\WebDriver.dll //C:\Users\user\.nuget\packages\system.speech\6.0.0\lib\net6.0\System.Speech.dll std::string references = R"(-r:C:\Users\user\.nuget\packages\dotnetseleniumextras.waithelpers\3.11.0\lib\net45\SeleniumExtras.WaitHelpers.dll -r:C:\Users\user\.nuget\packages\naudio\2.1.0\lib\net6.0\NAudio.dll -r:/C:\Users\user\.nuget\packages\selenium.support\4.4.0\lib\net5.0\WebDriver.Support.dll -r:C:\Users\user\.nuget\packages\selenium.webdriver\4.4.0\lib\net5.0\WebDriver.dll -r:C:\Users\user\.nuget\packages\system.speech\6.0.0\lib\net6.0\System.Speech.dll)"; std::string command = "mcs " + ProgramPath + ChromeInstPath + SeleniumWebPath + Mp3Path + references + R"( -target:library)"; //Compile the script std::string Command = std::string(R"(cd C:\Program Files (x86)\Mono\bin && )") + command; system(Command.c_str()); #pragma endregion #pragma region Init mono runtime mono_set_dirs("C:\\Program Files (x86)\\Mono\\lib", "C:\\Program Files (x86)\\Mono\\etc"); //Init a domain MonoDomain* domain; domain = mono_jit_init("MonoScriptTry"); if (!domain) { std::cout << "mono_jit_init failed" << std::endl; system("pause"); return 1; } //Open a assembly in the domain MonoAssembly* assembly; std::string assemblyPath = std::filesystem::path(get_working_path()).parent_path().string() + R"(\CMonoTest\Program.dll)"; assembly = mono_domain_assembly_open(domain, assemblyPath.c_str()); if (!assembly) { std::cout << "mono_domain_assembly_open failed" << std::endl; system("pause"); return 1; } //Get a image from the assembly MonoImage* image; image = mono_assembly_get_image(assembly); if (!image) { std::cout << "mono_assembly_get_image failed" << std::endl; system("pause"); return 1; } #pragma endregion #pragma region Run a static method { //Build a method description object MonoMethodDesc* TypeMethodDesc; const char* TypeMethodDescStr = "Program:StartWebRegister()"; TypeMethodDesc = mono_method_desc_new(TypeMethodDescStr, NULL); if (!TypeMethodDesc) { std::cout << "mono_method_desc_new failed" << std::endl; system("pause"); return 1; } //Search the method in the image MonoMethod* method; method = mono_method_desc_search_in_image(TypeMethodDesc, image); if (!method) { std::cout << "mono_method_desc_search_in_image failed" << std::endl; system("pause"); return 1; } //run the method std::cout << "Running the static method: " << TypeMethodDescStr << std::endl; mono_runtime_invoke(method, nullptr, nullptr, nullptr); } #pragma endregion #pragma endregion system("pause"); return 0; }
尝试通过-r:参数指定NuGet程序集完整路径仍报错,用msbuild构建.csproj后无法调用静态方法。请问在Mono中如何正确添加程序集引用?尤其是NuGet包场景(无.pc文件,无法用-pkg:参数)。
解决方案
1. 修复引用路径的语法错误
你的references字符串中有一处路径错误:-r:/C:\Users\user\.nuget\packages\selenium.support\4.4.0\lib\net5.0\WebDriver.Support.dll,多了一个前置斜杠/,应该改为-r:C:\Users\user\.nuget\packages\selenium.support\4.4.0\lib\net5.0\WebDriver.Support.dll。这个语法错误会导致mcs无法识别该引用。
2. 选择Mono兼容的.NET版本的NuGet包
Mono对.NET 5+的支持有限,优先选择**net4x系列(如net45、net462)**的NuGet包:
- 将NAudio替换为net45版本(而非net6.0)
- 将System.Speech替换为net462版本(而非net6.0)
- 将Selenium相关包替换为net45/net46版本(而非net5.0)
3. 确保编译时程序集可访问
除了用-r:指定完整路径,还可以:
- 将所有依赖的NuGet程序集复制到C#脚本所在的
CMonoTest目录,mcs会自动搜索当前目录的dll - 用
-lib:参数指定NuGet包的lib目录,减少路径长度,例如:
再配合-lib:C:\Users\user\.nuget\packages\naudio\2.1.0\lib\net45;C:\Users\user\.nuget\packages\system.speech\6.0.0\lib\net462-r:NAudio.dll、-r:System.Speech.dll来引用,避免长路径出错。
4. 解决msbuild构建后的调用问题
如果用msbuild构建.csproj:
- 确保项目目标框架设为net462(与Mono兼容)
- 编译生成的dll要放在C++程序能访问的路径,或者在
mono_domain_assembly_open时指定完整路径 - 检查
mono_method_desc_new的方法签名是否正确,要包含命名空间(如果有),例如YourNamespace.Program:StartWebRegister() - 调用
mono_runtime_invoke时,确保方法是静态无参数的,若有参数需传入正确的参数数组。
内容的提问来源于stack exchange,提问作者S.T.A.L.K.E.R
相关产品推荐
相关产品推荐

