IntPtr vs ref C#

Yel*_*low 9 c#

我必须将非托管的dll导入我的C#应用​​程序,我想知道IntPtr和ref之间有什么不同,你建议我使用什么,为什么?请注意,这两种方式对我都有用.例如:

[DllImport("mydll.dll", CallingConvention=CallingConvention.Cdecl)]
static extern Result Init(IntPtr versionInfo);

 [DllImport("mydll.dll", CallingConvention=CallingConvention.Cdecl)]
 public static extern Result Init(ref Version versionInfo);
Run Code Online (Sandbox Code Playgroud)

cdh*_*wie 5

如果Version是一个结构是与该EXTERN的结构兼容的Init功能期待,在这两个之间没有显著差异,只是ref版本将是一个很多更容易从C#使用以来,运行时将管理所有的编组和牵制了您.除非你真的想做所有这些工作,否则我会坚持ref选择.

当然,如果没有看到C函数原型,VersionC#中的结构,以及C中用于该参数的结构,我真的只能猜测.

  • 有一个潜在的显着差异:使用IntPtr允许将IntPtr.Zero作为值传递,而`ref Version`则不允许.因此,根据本机代码的要求,需要IntPtr重载并不罕见. (2认同)
  • @jonp:在这种情况下,你想要**两个**版本(一个重载函数),所以你可以通过引用传递一个`Version`,当你想要传递null时可以传递`IntPtr.Zero` .或者使`Version`成为一个类而不是一个struct,然后你可以传递null(并且不再需要`ref`关键字,但是在类上需要p/invoke注释属性). (2认同)

pst*_*jds 3

编辑:基于一些批评迫使我重新思考这一点并进一步研究。我坦率地承认 IntPtr 很容易出错,我认为对于“更难”的含义可能存在一些争论,但是如果框架可以自动编组它并让您不必固定东西等,如果您不使用 IntPtr 那么我认为我同意 IntPtr 会“更难。在我看来,经过进一步的研究,我认为声明你的结构会更容易(当你被迫 P/Invoke 并且无法制作 C++/CLI 包装器时)(在您的情况下版本)在托管代码中,然后通过 ref 参数传递它。

[StructLayout(LayoutKind.Sequential)]
struct Version
{
    // Data members
}

[DllImport("mydll.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern Result Init(ref Version versionInfo);
Run Code Online (Sandbox Code Playgroud)

我的猜测是你会想要 IntPtr 版本。区别在于 IntPtr 是一个管理指向内存的指针的类,而在参数列表中将参数声明为引用(ref 关键字)意味着您正在通过引用传递。通常,当通过 P/Invoke 调用向非托管 dll 传递数据或从非托管 dll 传递数据时,除非传递的数据是普通类型(int、double、string - 具有适当的 Marshal 装饰),否则我将数据作为 IntPtr 传递。然后,您可以将 IntPtr 编组到非托管结构的托管声明中。

您应该查看此链接以获取有关 P/Invoke 调用的更多信息: http://msdn.microsoft.com/en-us/magazine/cc164123.aspx