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

时间:2020-06-19 22:01:43

标签: c# .net c++-cli

是否可以通过引用将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
}

但这会返回编译器错误:

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变量类型,但结果相同。

有没有一种方法可以通过引用从.NET world将int传递给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的回答并没有更新上面的数字。

1 个答案:

答案 0 :(得分:0)

尝试像num一样直接使用ProcessOrder(num);失败,原因是原始帖子“ 无法将参数1从System::Int32 ^转换为int & ”,因为所传递的(指针)变量和预期的(引用)参数之间的间接级别不同。

尝试用ProcessOrder(*num);修复该错误,可以纠正间接寻址并获取匹配的类型,但编译失败,并出现错误“ gc堆中的对象(未装箱的值类型)无法转换为本地参考”。这指出了一个真正的问题,那就是未托管/未装箱的引用无法指向gc托管堆,这会受到压缩和重新排序。

最简单的解决方案是改为使用tracking reference int%,如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#调用者的情况。