我对C#很新,并且有一个简单的(?)问题。从非托管代码我收到一个int-pointer:
public foo(ref IntPtr state)
{
_myState = state;
}
_myState
是该班级的IntPtr
成员。现在我想通过_myState
与非托管C ++代码交换状态。如果我写这个,一切都有效:
public foo(ref IntPtr state)
{
_myState = state;
....do some stuff
state = 7;
}
在非托管应用程序中,我可以看到新值7
。但如果我写这个:
public foo(ref IntPtr state)
{
_myState = state;
...do some stuff
_myState = 7;
}
然后没有任何反应。状态的初始值为0
,将myState
更改为7
时,未在非托管应用程序中更新。
如何将状态参数中的_myState
等成员变量指定为“指针”,因此当状态更新时,_myState
也会更新?
在C ++中,这对指针来说没有问题......
好的,这是真正的代码:
[DllExport("QFX_InitializeInterfaceObject", CallingConvention = CallingConvention.StdCall)]
public static void QFX_InitializeInterfaceObject(
long windowHandle,
ref IntPtr processState)
{
ChartWindowHandle = (IntPtr)windowHandle;
OrderCommandProcessState = processState;
}
我想要的是OrderCommandProcessState
与processState
获得与其值相同的引用。
答案 0 :(得分:12)
首先,我想确保这一点是明确的:IntPtr只是一个整数,恰好与该机器架构上的本机指针大小相同 - 例如x64系统上的64位整数,例如。它不一定必须具有指针的语义,当然,互操作代码通常将指针填充到IntPtrs中作为一种安全地编组它们的方式。
继续讨论你的具体问题,让我们忽略它是一个IntPtr的事实。假装它只是一个int,因为它基本上就是这样:
public void Foo(ref int x) // x is an alias to another variable of type int.
{
int y = x; // y is a copy of the contents of x
y = 7; // The contents of y are no longer a copy of the contents of x
}
改变y不会以任何方式改变x; x是另一个变量的别名,y简要地拥有该变量内容的副本。它绝不是同一个变量的别名。
如何将一个变量作为另一个变量的别名,所以当更新一个变量的状态时,链接变量也会更新?在C ++中,指针没有问题。
今天在安全子集中,您只能通过方法的“ref”和“out”参数来实现。 “ref”参数成为给定变量的别名。 这是您可以直接将一个变量转换为另一个变量的唯一安全方式。
CLR也支持ref locals。我们可以实现这样的功能,事实上我已经用C#对其进行了原型化。在我的原型中你可以说:
public void Foo(ref int x) // x is an alias to another variable of type int.
{
ref int y = ref x; // y is now an alias to the same variable that x aliases!
y = 7; // changing y now changes x, and whatever x
// aliases, because those are all the same variable
}
但是我们还没有将这个功能添加到C#中,并且没有计划很快就这样做。如果你有一个引人注目的使用案例,我很乐意听到它。 (更新:该功能已添加到C#7中。)
(CLR还允许“ref”返回类型。但是,CLR不允许为变量创建别名,然后将该别名存储在字段中!字段的生命周期可能比链接变量长,并且CLR设计者希望避免困扰C和C ++的那类错误。)
如果您知道变量固定在内存中的特定位置,那么您可以关闭安全系统并指向该变量;然后你有一个完全普通的指针,你可以像在C ++中那样使用它。 (也就是说,如果指针ptr
引用变量,则*ptr
是该变量的别名。)
unsafe public void Foo(int* x) // *x is an alias to a variable of type int.
{
int* y = x; // *y is now an alias to the same variable that *x aliases
*y = 7; // changing *y now changes *x, and whatever *x
// aliases, because those are all the same variable
}
CLR对如何使用指针没有任何限制;如果需要,您可以自由地将它们存储在字段中。但是,如果关闭安全系统,那么你负责确保垃圾收集器(或任何内存管理器拥有该存储 - 它可能不是托管内存)不会在指针的生命周期中更改别名变量的位置。除非你真的知道你在做什么,否则不要关闭那个安全系统;那个安全系统可以保护你。