如何通过引用将 int 从 C# 传递到 C++?

How to pass an int from C# to C++ by reference?

是否可以通过引用将 int 从 C# 传递到 C++?

我在 C++ 中有一个简单的方法,它只增加一个数字并打印消息。

void ProcessOrder(int& num)
{
    int start = num;
    int stop = num + 10;

    for (int i = start; i < stop; i++)
    {
        cout << "[Legacy] counting " << i << endl;
    }

    cout << endl;

    // Note the above was original posted code and I made a stupid mistake and was never
    // even changing `num` value passed by reference. The correct function to test
    // should be as below (discard all of the above)
    num =  num + 5; // just modify the number to any value
}

现在我想从 C++/CLI 调用它,然后从 C# 调用它。

void StoreWrapper::ProcessOrder(int^ num)
{
    LegacyStore* legacyStore = new LegacyStore();
    legacyStore->ProcessOrder(num); // error here
}

但是这个returns编译器错误:

error C2664: 'void LegacyStore::ProcessOrder(int &)': cannot convert argument 1 from 'System::Int32 ^' to 'int &'

我确定所有三个项目都是 x86,但错误仍然存​​在。作为价格,CLR 模块是 Win32,C# 控制台应用程序是 x86。

问题在这里:

如果我声明 void StoreWrapper::ProcessOrder(int& num) 那么这个方法可以编译,但现在我相信它是纯 C++?我无法从 C# 端调用它,得到以下编译器错误:

error CS1503: Argument 1: cannot convert from 'int' to 'int*'

如果我将其声明为“void StoreWrapper::ProcessOrder(int^ num)”,那么该方法甚至无法编译。

我尝试使用 System::Int32 变量类型但结果相同。

有没有办法通过引用将 int 从 .NET 世界传递给 C++?如果 C++ 端是 32 位而 .NET 端是 64 位,是否可能?

更新

C# 代码在这里,基本上我希望在下面的代码中更新数字。

  int number = 0;
  Console.WriteLine("Original number = {0}", number);
  store.ProcessOrder(ref number);
  Console.WriteLine("After ProcessOrder number = {0}", number);

不幸的是,dxiv 的回答没有更新上面的数字。

尝试像 ProcessOrder(num); 一样直接使用 num 失败,并出现原始 post 中引用的错误“无法将参数 1 从 System::Int32 ^ 转换为int &" 因为传递的(指针)变量和期望的(引用)参数之间的间接级别不同。

尝试使用 ProcessOrder(*num); 修复此问题会纠正间接寻址并获取匹配的类型,但无法编译并出现错误“来自 gc 堆的对象(未装箱的值类型)无法转换为本机引用”。这指向了真正的问题,即 unmanaged/unboxed 引用无法指向 gc 管理的堆,该堆会受到压缩和重新洗牌的影响。

最简单的解决方案是使用 tracking reference int% instead, as advised in the answer 作为副本链接的问题。

void StoreWrapper::ProcessOrder(int% num)
{
    LegacyStore* legacyStore = new LegacyStore();

    legacyStore->ProcessOrder(*&num);  // shorthand for:
                                       //
                                       // int &n = *&num;
                                       // legacyStore->ProcessOrder(n);
                                       // num = n;
}

// to be called from C# as:
//
// int number = 0;
// store.ProcessOrder(ref number);


[ EDIT ] 也可以通过地址使用 num,尽管这需要显式固定。

void StoreWrapper::ProcessOrder([System::Runtime::InteropServices::Out] int %num)
{
    LegacyStore* legacyStore = new LegacyStore();

    pin_ptr<int> p = &num;
    legacyStore->ProcessOrder(*p);
}

// to be called from C# as:
//
// int number = 0;
// store.ProcessOrder(out number);


[ EDIT #2 ] 编辑代码并添加注释以涵盖将值返回给 C# 调用方。