在.NET平台调用中使用不安全的struct *作为opaque类型而不是IntPtr是否有效?

时间:2010-12-21 20:52:04

标签: c# pinvoke

.NET平台调用主张将指针类型声明为IntPtr。例如,以下

[DllImport("mylib")]
static extern IntPtr get_foo();

[DllImport("mylib")]
static extern void do_something_foo(IntPtr foo);

但是,我发现当与具有许多指针类型的有趣本机接口连接时,将所有内容展平为IntPtr会使代码非常难以阅读并消除编译器可以执行的典型类型检查。

我一直在使用一种模式,我声明一个不安全的结构是一个不透明的指针类型。我可以将此指针类型存储在托管对象中,编译器可以为我进行类型检查。例如:

class Foo {
   unsafe struct FOO {};  // opaque type
   unsafe FOO *my_foo;

   class if {
     [DllImport("mydll")]
     extern static unsafe FOO* get_foo();

     [DllImport("mydll")]
     extern static unsafe void do_something_foo(FOO *foo);
   }

   public unsafe Foo() {
     this.my_foo = if.get_foo();     
   }
   public unsafe do_something_foo() {
     if.do_something_foo(this.my_foo);
   }

注意:我不是要编组一个结构。 DLL提供了一个我不应该触摸的不透明指针,我只需要将它提供给将来调用DLL。

我知道发布的方法是IntPtr,但我不喜欢使用无类型指针。当托管类型和本机代码之间存在多种指针类型时,使用IntPtrs非常危险。使用我的opaque结构指针类型进行类型检查是天赐之物。

我在实践中使用这种技术没有遇到任何麻烦。但是,我还没有看到任何人使用这种技术的例子,我想知道为什么。在.NET运行时看来,上述代码是否有任何原因无效?

我的主要问题是.NET GC系统如何处理“不安全的FOO * my_foo”。我希望因为底层类型是一个结构,并且它被声明为不安全,GC会忽略它。

这个指针是GC系统试图追踪的东西,还是只是忽略它?使用我的技术而不是IntPtr是否安全?

2 个答案:

答案 0 :(得分:2)

似乎答案是“是”......“不安全的指针被视为值类型”,这意味着使用它们存储不透明类型是安全的。从某种意义上说,它们就像IntPtr一样工作,但它们带有额外的类型检查,因为不同类型的不安全指针不被认为是相同的,就像它们将它们全部设置为IntPtr一样。

有关该主题的更详细的文章,请查看..

http://www.codeproject.com/script/Articles/ArticleVersion.aspx?waid=1210&aid=339290

答案 1 :(得分:-1)

我不会使用不安全的代码和指针。为什么不简单地定义结构并让CLR进行映射:

[StructLayout(LayoutKind.Sequential)]
public struct Foo
{
    public int Field1;
    public long Field2;
}

然后:

[DllImport("mylib")]
static extern void do_something_foo(ref Foo foo);