You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 14:45:37