如何通过引用将 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 = *#
// 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 = #
legacyStore->ProcessOrder(*p);
}
// to be called from C# as:
//
// int number = 0;
// store.ProcessOrder(out number);
[ EDIT #2 ] 编辑代码并添加注释以涵盖将值返回给 C# 调用方。
是否可以通过引用将 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 = *#
// 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 = #
legacyStore->ProcessOrder(*p);
}
// to be called from C# as:
//
// int number = 0;
// store.ProcessOrder(out number);
[ EDIT #2 ] 编辑代码并添加注释以涵盖将值返回给 C# 调用方。